bon_macros/builder/builder_gen/member/config/with/
closure.rs1use crate::parsing::SimpleClosure;
2use crate::util::prelude::*;
3use darling::FromMeta;
4
5const INVALID_RETURN_TYPE_ERROR: &str = "\
6expected one of the following:
7
8(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(*);
11
12(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>`);
16
17 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;
19
20 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;
23
24(*) 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";
27
28#[derive(Debug)]
29pub(crate) struct SetterClosure {
30 pub(crate) inputs: Vec<SetterClosureInput>,
31 pub(crate) body: Box<syn::Expr>,
32 pub(crate) output: Option<SetterClosureOutput>,
33}
34
35#[derive(Debug)]
36pub(crate) struct SetterClosureOutput {
37 pub(crate) result_path: syn::Path,
38 pub(crate) err_ty: Option<syn::Type>,
39}
40
41#[derive(Debug)]
42pub(crate) struct SetterClosureInput {
43 pub(crate) pat: syn::PatIdent,
44 pub(crate) ty: Box<syn::Type>,
45}
46
47impl FromMeta for SetterClosure {
48 fn from_meta(item: &syn::Meta) -> Result<Self> {
49 let closure = SimpleClosure::from_meta(item)?;
50
51 let inputs = closure
52 .inputs
53 .into_iter()
54 .map(|input| {
55 Ok(SetterClosureInput {
56 ty: input.ty.ok_or_else(|| {
57 err!(&input.pat, "expected a type for the setter input parameter")
58 })?,
59 pat: input.pat,
60 })
61 })
62 .collect::<Result<_>>()?;
63
64 let return_type = match closure.output {
65 syn::ReturnType::Default => None,
66 syn::ReturnType::Type(_, ty) => {
67 let err = || err!(&ty, "{INVALID_RETURN_TYPE_ERROR}");
68
69 let ty = ty
70 .as_generic_angle_bracketed_path(|last_segment| {
71 last_segment.to_string().ends_with("Result")
74 })
75 .ok_or_else(err)?;
76
77 if !(1..=2).contains(&ty.args.len()) {
78 return Err(err());
79 }
80
81 let mut args = ty.args.iter();
82 let ok_ty = args.next().ok_or_else(err)?;
83
84 if !matches!(ok_ty, syn::GenericArgument::Type(syn::Type::Infer(_))) {
85 return Err(err());
86 }
87
88 let err_ty = args
89 .next()
90 .map(|arg| match arg {
91 syn::GenericArgument::Type(ty) => Ok(ty.clone()),
92 _ => Err(err()),
93 })
94 .transpose()?;
95
96 let mut result_path = ty.path.clone();
97
98 result_path
102 .segments
103 .last_mut()
104 .expect("BUG: segments can't be empty")
105 .arguments = syn::PathArguments::None;
106
107 Some(SetterClosureOutput {
108 result_path,
109 err_ty,
110 })
111 }
112 };
113
114 Ok(Self {
115 inputs,
116 body: closure.body,
117 output: return_type,
118 })
119 }
120}