bon_macros/builder/builder_gen/
builder_derives.rs

1use super::top_level_config::{DeriveConfig, DerivesConfig};
2use super::BuilderGenCtx;
3use crate::builder::builder_gen::Member;
4use crate::util::prelude::*;
5use darling::ast::GenericParamExt;
6
7impl BuilderGenCtx {
8    pub(crate) fn builder_derives(&self) -> TokenStream {
9        let DerivesConfig { clone, debug } = &self.builder_type.derives;
10
11        let mut tokens = TokenStream::new();
12
13        if let Some(derive) = clone {
14            tokens.extend(self.derive_clone(derive));
15        }
16
17        if let Some(derive) = debug {
18            tokens.extend(self.derive_debug(derive));
19        }
20
21        tokens
22    }
23
24    /// We follow the logic of the standard `#[derive(...)]` macros such as `Clone` and `Debug`.
25    /// They add bounds of their respective traits to every generic type parameter on the struct
26    /// without trying to analyze if that bound is actually required for the derive to work, so
27    /// it's a conservative approach.
28    ///
29    /// However, the user can also override these bounds using the `bounds(...)` attribute for
30    /// the specific derive.
31    fn where_clause_for_derive(
32        &self,
33        target_trait_bounds: &TokenStream,
34        derive: &DeriveConfig,
35    ) -> TokenStream {
36        let derive_specific_predicates = derive
37            .bounds
38            .as_ref()
39            .map(ToTokens::to_token_stream)
40            .unwrap_or_else(|| {
41                let bounds = self
42                    .generics
43                    .decl_without_defaults
44                    .iter()
45                    .filter_map(syn::GenericParam::as_type_param)
46                    .map(|param| {
47                        let ident = &param.ident;
48                        quote! {
49                            #ident: #target_trait_bounds
50                        }
51                    });
52
53                quote! {
54                    #( #bounds, )*
55                }
56            });
57
58        let inherent_item_predicates = self.generics.where_clause_predicates();
59
60        quote! {
61            where
62                #( #inherent_item_predicates, )*
63                #derive_specific_predicates
64        }
65    }
66
67    fn derive_clone(&self, derive: &DeriveConfig) -> TokenStream {
68        let bon = &self.bon;
69        let generics_decl = &self.generics.decl_without_defaults;
70        let generic_args = &self.generics.args;
71        let builder_ident = &self.builder_type.ident;
72
73        let clone = quote!(::core::clone::Clone);
74
75        let clone_receiver = self.receiver().map(|receiver| {
76            let ty = &receiver.without_self_keyword;
77            quote! {
78                __unsafe_private_receiver: <#ty as #clone>::clone(&self.__unsafe_private_receiver),
79            }
80        });
81
82        let clone_start_fn_args = self.start_fn_args().next().map(|_| {
83            let types = self.start_fn_args().map(|arg| &arg.base.ty.norm);
84            let indices = self.start_fn_args().map(|arg| &arg.index);
85
86            quote! {
87                // We clone named members individually instead of cloning
88                // the entire tuple to improve error messages in case if
89                // one of the members doesn't implement `Clone`. This avoids
90                // a sentence that say smth like
91                // ```
92                // required for `(...big type...)` to implement `Clone`
93                // ```
94                __unsafe_private_start_fn_args: (
95                    #( <#types as #clone>::clone(&self.__unsafe_private_start_fn_args.#indices), )*
96                ),
97            }
98        });
99
100        let where_clause = self.where_clause_for_derive(&clone, derive);
101        let state_mod = &self.state_mod.ident;
102
103        let clone_named_members = self.named_members().map(|member| {
104            let member_index = &member.index;
105
106            // The type hint here is necessary to get better error messages
107            // that point directly to the type that doesn't implement `Clone`
108            // in the input code using the span info from the type hint.
109            let ty = member.underlying_norm_ty();
110
111            quote! {
112                #bon::__::better_errors::clone_member::<#ty>(
113                    &self.__unsafe_private_named.#member_index
114                )
115            }
116        });
117
118        let clone_fields = self.custom_fields().map(|member| {
119            let member_ident = &member.ident;
120            let member_ty = &member.norm_ty;
121
122            quote! {
123                // The type hint here is necessary to get better error messages
124                // that point directly to the type that doesn't implement `Clone`
125                // in the input code using the span info from the type hint.
126                #member_ident: <#member_ty as #clone>::clone(&self.#member_ident)
127            }
128        });
129
130        let state_var = &self.state_var;
131
132        quote! {
133            #[automatically_derived]
134            impl<
135                #(#generics_decl,)*
136                #state_var: #state_mod::State
137            >
138            #clone for #builder_ident<
139                #(#generic_args,)*
140                #state_var
141            >
142            #where_clause
143            {
144                fn clone(&self) -> Self {
145                    Self {
146                        __unsafe_private_phantom: ::core::marker::PhantomData,
147                        #clone_receiver
148                        #clone_start_fn_args
149                        #( #clone_fields, )*
150
151                        // We clone named members individually instead of cloning
152                        // the entire tuple to improve error messages in case if
153                        // one of the members doesn't implement `Clone`. This avoids
154                        // a sentence that say smth like
155                        // ```
156                        // required for `(...big type...)` to implement `Clone`
157                        // ```
158                        __unsafe_private_named: ( #( #clone_named_members, )* ),
159                    }
160                }
161            }
162        }
163    }
164
165    fn derive_debug(&self, derive: &DeriveConfig) -> TokenStream {
166        let bon = &self.bon;
167
168        let format_members = self.members.iter().filter_map(|member| {
169            match member {
170                Member::StartFn(member) => {
171                    let member_index = &member.index;
172                    let member_ident_str = member.base.ident.to_string();
173                    let member_ty = &member.base.ty.norm;
174                    Some(quote! {
175                        output.field(
176                            #member_ident_str,
177                            #bon::__::better_errors::as_dyn_debug::<#member_ty>(
178                                &self.__unsafe_private_start_fn_args.#member_index
179                            )
180                        );
181                    })
182                }
183                Member::Field(member) => {
184                    let member_ident = &member.ident;
185                    let member_ident_str = member_ident.to_string();
186                    let member_ty = &member.norm_ty;
187                    Some(quote! {
188                        output.field(
189                            #member_ident_str,
190                            #bon::__::better_errors::as_dyn_debug::<#member_ty>(
191                                &self.#member_ident
192                            )
193                        );
194                    })
195                }
196                Member::Named(member) => {
197                    let member_index = &member.index;
198                    let member_ident_str = &member.name.snake_raw_str;
199                    let member_ty = member.underlying_norm_ty();
200                    Some(quote! {
201                        if let Some(value) = &self.__unsafe_private_named.#member_index {
202                            output.field(
203                                #member_ident_str,
204                                #bon::__::better_errors::as_dyn_debug::<#member_ty>(value)
205                            );
206                        }
207                    })
208                }
209
210                // The values for these members are computed only in the finishing
211                // function where the builder is consumed, and they aren't stored
212                // in the builder itself.
213                Member::FinishFn(_) | Member::Skip(_) => None,
214            }
215        });
216
217        let format_receiver = self.receiver().map(|receiver| {
218            let ty = &receiver.without_self_keyword;
219            quote! {
220                output.field(
221                    "self",
222                    #bon::__::better_errors::as_dyn_debug::<#ty>(
223                        &self.__unsafe_private_receiver
224                    )
225                );
226            }
227        });
228
229        let debug = quote!(::core::fmt::Debug);
230        let where_clause = self.where_clause_for_derive(&debug, derive);
231        let state_mod = &self.state_mod.ident;
232        let generics_decl = &self.generics.decl_without_defaults;
233        let generic_args = &self.generics.args;
234        let builder_ident = &self.builder_type.ident;
235        let state_var = &self.state_var;
236        let builder_ident_str = builder_ident.to_string();
237
238        quote! {
239            #[automatically_derived]
240            impl<
241                #(#generics_decl,)*
242                #state_var: #state_mod::State
243            >
244            #debug for #builder_ident<
245                #(#generic_args,)*
246                #state_var
247            >
248            #where_clause
249            {
250                fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
251                    let mut output = f.debug_struct(#builder_ident_str);
252
253                    #format_receiver
254                    #(#format_members)*
255
256                    output.finish()
257                }
258            }
259        }
260    }
261}