1use crate::parsing::SimpleClosure;
2use crate::util::prelude::*;
3use darling::FromMeta;
45const INVALID_RETURN_TYPE_ERROR: &str = "\
6expected one of the following:
78(1) no return type annotation;
9 this means the closure is expected to return a value of the same type
10 as the member's underlying type(*);
1112(2) `-> *Result<_, {{ErrorType}}>` or `-> *Result<_>` return type annotation;
13 this means the closure is expected to return a `Result` where the `Ok`
14 variant is of the same type as the member's underlying type(*); this syntax
15 allows you to define a fallbile setter (one that returns a `Result<Builder>`);
1617 the `_` placeholder must be spelled literally to mark the underlying type(*)
18 of the member; an optional second generic parameter for the error type is allowed;
1920 the return type doesn't have to be named `Result` exactly, the only requirement is
21 that it must have the `Result` suffix; for example if you have a type alias
22 `ApiResult<_>`, then it'll work fine;
2324(*) underlying type is the type of the member stripped from the `Option<T>` wrapper
25 if this member is of `Option<T>` type and no `#[builder(required)]` annotation
26 is present";
2728#[derive(Debug)]
29pub(crate) struct SetterClosure {
30pub(crate) inputs: Vec<SetterClosureInput>,
31pub(crate) body: Box<syn::Expr>,
32pub(crate) output: Option<SetterClosureOutput>,
33}
3435#[derive(Debug)]
36pub(crate) struct SetterClosureOutput {
37pub(crate) result_path: syn::Path,
38pub(crate) err_ty: Option<syn::Type>,
39}
4041#[derive(Debug)]
42pub(crate) struct SetterClosureInput {
43pub(crate) pat: syn::PatIdent,
44pub(crate) ty: Box<syn::Type>,
45}
4647impl FromMeta for SetterClosure {
48fn from_meta(item: &syn::Meta) -> Result<Self> {
49let closure = SimpleClosure::from_meta(item)?;
5051let inputs = closure
52 .inputs
53 .into_iter()
54 .map(|input| {
55Ok(SetterClosureInput {
56 ty: input.ty.ok_or_else(|| {
57err!(&input.pat, "expected a type for the setter input parameter")
58 })?,
59 pat: input.pat,
60 })
61 })
62 .collect::<Result<_>>()?;
6364let return_type = match closure.output {
65 syn::ReturnType::Default => None,
66 syn::ReturnType::Type(_, ty) => {
67let err = || err!(&ty, "{INVALID_RETURN_TYPE_ERROR}");
6869let ty = ty
70 .as_generic_angle_bracketed_path(|last_segment| {
71// We allow for arbitrary `Result` type variations
72 // including custom type aliases like `ApiResult<_>`
73last_segment.to_string().ends_with("Result")
74 })
75 .ok_or_else(err)?;
7677if !(1..=2).contains(&ty.args.len()) {
78return Err(err());
79 }
8081let mut args = ty.args.iter();
82let ok_ty = args.next().ok_or_else(err)?;
8384if !matches!(ok_ty, syn::GenericArgument::Type(syn::Type::Infer(_))) {
85return Err(err());
86 }
8788let err_ty = args
89 .next()
90 .map(|arg| match arg {
91 syn::GenericArgument::Type(ty) => Ok(ty.clone()),
92_ => Err(err()),
93 })
94 .transpose()?;
9596let mut result_path = ty.path.clone();
9798// We store the error type of the result separately.
99 // Strip the generic arguments, because we only care
100 // about the path of the `Result` in `result_path` field.
101result_path
102 .segments
103 .last_mut()
104 .expect("BUG: segments can't be empty")
105 .arguments = syn::PathArguments::None;
106107Some(SetterClosureOutput {
108 result_path,
109 err_ty,
110 })
111 }
112 };
113114Ok(Self {
115 inputs,
116 body: closure.body,
117 output: return_type,
118 })
119 }
120}