typed_builder_macro/
struct_info.rs

1use proc_macro2::{Ident, Span, TokenStream};
2use quote::{format_ident, quote, quote_spanned, ToTokens};
3use syn::{parse::Error, parse_quote, punctuated::Punctuated, GenericArgument, ItemFn, Token};
4
5use crate::builder_attr::{IntoSetting, TypeBuilderAttr};
6use crate::field_info::FieldInfo;
7use crate::mutator::Mutator;
8use crate::util::{
9    empty_type, empty_type_tuple, first_visibility, modify_types_generics_hack, phantom_data_for_generics, public_visibility,
10    strip_raw_ident_prefix, type_tuple,
11};
12
13#[derive(Debug)]
14pub struct StructInfo<'a> {
15    vis: &'a syn::Visibility,
16    name: &'a syn::Ident,
17    generics: &'a syn::Generics,
18    fields: Vec<FieldInfo<'a>>,
19
20    builder_attr: TypeBuilderAttr<'a>,
21    builder_name: syn::Ident,
22}
23
24impl<'a> StructInfo<'a> {
25    fn included_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
26        self.fields.iter().filter(|f| f.builder_attr.setter.skip.is_none())
27    }
28    fn setter_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
29        self.included_fields().filter(|f| f.builder_attr.via_mutators.is_none())
30    }
31
32    fn generic_arguments(&self) -> Punctuated<GenericArgument, Token![,]> {
33        self.generics
34            .params
35            .iter()
36            .map(|generic_param| match generic_param {
37                syn::GenericParam::Type(type_param) => {
38                    let ident = type_param.ident.to_token_stream();
39                    syn::parse2(ident).unwrap()
40                }
41                syn::GenericParam::Lifetime(lifetime_def) => syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone()),
42                syn::GenericParam::Const(const_param) => {
43                    let ident = const_param.ident.to_token_stream();
44                    syn::parse2(ident).unwrap()
45                }
46            })
47            .collect()
48    }
49
50    pub fn new(ast: &'a syn::DeriveInput, fields: impl Iterator<Item = &'a syn::Field>) -> syn::Result<StructInfo<'a>> {
51        let builder_attr = TypeBuilderAttr::new(&ast.attrs)?;
52        let builder_name = builder_attr
53            .builder_type
54            .get_name()
55            .map(|name| strip_raw_ident_prefix(name.to_string()))
56            .unwrap_or_else(|| strip_raw_ident_prefix(format!("{}Builder", ast.ident)));
57        Ok(StructInfo {
58            vis: &ast.vis,
59            name: &ast.ident,
60            generics: &ast.generics,
61            fields: fields
62                .enumerate()
63                .map(|(i, f)| FieldInfo::new(i, f, builder_attr.field_defaults.clone()))
64                .collect::<Result<_, _>>()?,
65            builder_attr,
66            builder_name: syn::Ident::new(&builder_name, proc_macro2::Span::call_site()),
67        })
68    }
69
70    fn builder_creation_impl(&self) -> syn::Result<TokenStream> {
71        let StructInfo {
72            vis,
73            ref name,
74            ref builder_name,
75            ..
76        } = *self;
77        let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
78        let init_fields_type = type_tuple(self.included_fields().map(|f| {
79            if f.builder_attr.via_mutators.is_some() {
80                f.tuplized_type_ty_param()
81            } else {
82                empty_type()
83            }
84        }));
85        let init_fields_expr = self.included_fields().map(|f| {
86            f.builder_attr.via_mutators.as_ref().map_or_else(
87                || quote!(()),
88                |via_mutators| {
89                    let init = &via_mutators.init;
90                    quote!((#init,))
91                },
92            )
93        });
94        let mut all_fields_param_type: syn::TypeParam =
95            syn::Ident::new("TypedBuilderFields", proc_macro2::Span::call_site()).into();
96        let all_fields_param = syn::GenericParam::Type(all_fields_param_type.clone());
97        all_fields_param_type.default = Some(syn::Type::Tuple(init_fields_type.clone()));
98        let b_generics = {
99            let mut generics = self.generics.clone();
100            generics.params.push(syn::GenericParam::Type(all_fields_param_type));
101            generics
102        };
103        let generics_with_empty = modify_types_generics_hack(&ty_generics, |args| {
104            args.push(syn::GenericArgument::Type(init_fields_type.clone().into()));
105        });
106        let phantom_data = phantom_data_for_generics(self.generics);
107
108        let builder_method_name = self.builder_attr.builder_method.get_name().unwrap_or_else(|| quote!(builder));
109        let builder_method_visibility = first_visibility(&[
110            self.builder_attr.builder_method.vis.as_ref(),
111            self.builder_attr.builder_type.vis.as_ref(),
112            Some(vis),
113        ]);
114        let builder_method_doc = self.builder_attr.builder_method.get_doc_or(|| {
115            format!(
116                "
117                Create a builder for building `{name}`.
118                On the builder, call {setters} to set the values of the fields.
119                Finally, call `.{build_method_name}()` to create the instance of `{name}`.
120                ",
121                name = self.name,
122                build_method_name = self.build_method_name(),
123                setters = {
124                    let mut result = String::new();
125                    let mut is_first = true;
126                    for field in self.setter_fields() {
127                        use std::fmt::Write;
128                        if is_first {
129                            is_first = false;
130                        } else {
131                            write!(&mut result, ", ").unwrap();
132                        }
133                        write!(&mut result, "`.{}(...)`", field.name).unwrap();
134                        if field.builder_attr.default.is_some() {
135                            write!(&mut result, "(optional)").unwrap();
136                        }
137                    }
138                    result
139                }
140            )
141        });
142
143        let builder_type_visibility = first_visibility(&[self.builder_attr.builder_type.vis.as_ref(), Some(vis)]);
144        let builder_type_doc = if self.builder_attr.doc {
145            self.builder_attr.builder_type.get_doc_or(|| {
146                format!(
147                    "
148                    Builder for [`{name}`] instances.
149
150                    See [`{name}::{builder_method_name}()`] for more info.
151                    ",
152                    name = name,
153                    builder_method_name = builder_method_name
154                )
155            })
156        } else {
157            quote!(#[doc(hidden)])
158        };
159
160        let (b_generics_impl, b_generics_ty, b_generics_where_extras_predicates) = b_generics.split_for_impl();
161        let mut b_generics_where: syn::WhereClause = syn::parse2(quote! {
162            where TypedBuilderFields: Clone
163        })?;
164        if let Some(predicates) = b_generics_where_extras_predicates {
165            b_generics_where.predicates.extend(predicates.predicates.clone());
166        }
167
168        Ok(quote! {
169            #[automatically_derived]
170            impl #impl_generics #name #ty_generics #where_clause {
171                #builder_method_doc
172                #[allow(dead_code, clippy::default_trait_access)]
173                #builder_method_visibility fn #builder_method_name() -> #builder_name #generics_with_empty {
174                    #builder_name {
175                        fields: (#(#init_fields_expr,)*),
176                        phantom: ::core::default::Default::default(),
177                    }
178                }
179            }
180
181            #[must_use]
182            #builder_type_doc
183            #[allow(dead_code, non_camel_case_types, non_snake_case)]
184            #builder_type_visibility struct #builder_name #b_generics #b_generics_where_extras_predicates {
185                fields: #all_fields_param,
186                phantom: #phantom_data,
187            }
188
189            #[automatically_derived]
190            impl #b_generics_impl Clone for #builder_name #b_generics_ty #b_generics_where {
191                #[allow(clippy::default_trait_access)]
192                fn clone(&self) -> Self {
193                    Self {
194                        fields: self.fields.clone(),
195                        phantom: ::core::default::Default::default(),
196                    }
197                }
198            }
199        })
200    }
201
202    fn field_impl(&self, field: &FieldInfo) -> syn::Result<TokenStream> {
203        let StructInfo { ref builder_name, .. } = *self;
204
205        let destructuring = self
206            .included_fields()
207            .map(|f| {
208                if f.ordinal == field.ordinal {
209                    quote!(())
210                } else {
211                    let name = f.name;
212                    name.to_token_stream()
213                }
214            })
215            .collect::<Vec<_>>();
216        let reconstructing = self.included_fields().map(|f| f.name).collect::<Vec<_>>();
217
218        let &FieldInfo {
219            name: field_name,
220            ty: field_type,
221            ..
222        } = field;
223        let mut ty_generics = self.generic_arguments();
224        let mut target_generics_tuple = empty_type_tuple();
225        let mut ty_generics_tuple = empty_type_tuple();
226        let generics = {
227            let mut generics = self.generics.clone();
228            for f in self.included_fields() {
229                if f.ordinal == field.ordinal {
230                    ty_generics_tuple.elems.push_value(empty_type());
231                    target_generics_tuple.elems.push_value(f.tuplized_type_ty_param());
232                } else {
233                    generics.params.push(f.generic_ty_param());
234                    let generic_argument: syn::Type = f.type_ident();
235                    ty_generics_tuple.elems.push_value(generic_argument.clone());
236                    target_generics_tuple.elems.push_value(generic_argument);
237                }
238                ty_generics_tuple.elems.push_punct(Default::default());
239                target_generics_tuple.elems.push_punct(Default::default());
240            }
241            generics
242        };
243        let mut target_generics = ty_generics.clone();
244        target_generics.push(syn::GenericArgument::Type(target_generics_tuple.into()));
245        ty_generics.push(syn::GenericArgument::Type(ty_generics_tuple.into()));
246        let (impl_generics, _, where_clause) = generics.split_for_impl();
247        let doc = if let Some(doc) = field.builder_attr.setter.doc.as_ref() {
248            Some(quote!(#[doc = #doc]))
249        } else if !field.builder_attr.doc_comments.is_empty() {
250            Some(
251                field
252                    .builder_attr
253                    .doc_comments
254                    .iter()
255                    .map(|&line| quote!(#[doc = #line]))
256                    .collect(),
257            )
258        } else {
259            None
260        };
261
262        let deprecated = &field.builder_attr.deprecated;
263
264        let option_was_stripped;
265        let arg_type = if field.builder_attr.setter.strip_option.is_some() && field.builder_attr.setter.transform.is_none() {
266            if let Some(inner_type) = field.type_from_inside_option() {
267                option_was_stripped = true;
268                inner_type
269            } else if field
270                .builder_attr
271                .setter
272                .strip_option
273                .as_ref()
274                .map_or(false, |s| s.ignore_invalid)
275            {
276                option_was_stripped = false;
277                field_type
278            } else {
279                return Err(Error::new_spanned(
280                    field_type,
281                    "can't `strip_option` - field is not `Option<...>`",
282                ));
283            }
284        } else {
285            option_was_stripped = false;
286            field_type
287        };
288        let (arg_type, arg_expr) = if field.builder_attr.setter.auto_into.is_some() {
289            (quote!(impl ::core::convert::Into<#arg_type>), quote!(#field_name.into()))
290        } else {
291            (arg_type.to_token_stream(), field_name.to_token_stream())
292        };
293
294        let strip_bool_fallback = field
295            .builder_attr
296            .setter
297            .strip_bool
298            .as_ref()
299            .and_then(|strip_bool| strip_bool.fallback.as_ref())
300            .map(|fallback| (fallback.clone(), quote!(#field_name: #field_type), quote!(#arg_expr)));
301
302        let strip_option_fallback = field.builder_attr.setter.strip_option.as_ref().and_then(|strip_option| {
303            if let Some(ref fallback) = strip_option.fallback {
304                Some((fallback.clone(), quote!(#field_name: #field_type), quote!(#arg_expr)))
305            } else if strip_option.fallback_prefix.is_none() && strip_option.fallback_suffix.is_none() {
306                None
307            } else {
308                let prefix = strip_option.fallback_prefix.as_deref().unwrap_or_default();
309                let suffix = strip_option.fallback_suffix.as_deref().unwrap_or_default();
310                let fallback_name = syn::Ident::new(&format!("{}{}{}", prefix, field_name, suffix), field_name.span());
311                Some((fallback_name, quote!(#field_name: #field_type), quote!(#arg_expr)))
312            }
313        });
314
315        let (param_list, arg_expr) = if field.builder_attr.setter.strip_bool.is_some() {
316            (quote!(), quote!(true))
317        } else if let Some(transform) = &field.builder_attr.setter.transform {
318            let params = transform.params.iter().map(|(pat, ty)| quote!(#pat: #ty));
319            let body = &transform.body;
320            (quote!(#(#params),*), quote!({ #body }))
321        } else if option_was_stripped {
322            (quote!(#field_name: #arg_type), quote!(Some(#arg_expr)))
323        } else {
324            (quote!(#field_name: #arg_type), arg_expr)
325        };
326
327        let repeated_fields_error_type_name = syn::Ident::new(
328            &format!(
329                "{}_Error_Repeated_field_{}",
330                builder_name,
331                strip_raw_ident_prefix(field_name.to_string())
332            ),
333            proc_macro2::Span::call_site(),
334        );
335        let repeated_fields_error_message = format!("Repeated field {}", field_name);
336
337        let method_name = field.setter_method_name();
338
339        let strip_option_fallback_method = if let Some((method_name, param_list, arg_expr)) = strip_option_fallback {
340            Some(quote! {
341                #deprecated
342                #doc
343                #[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
344                pub fn #method_name (self, #param_list) -> #builder_name <#target_generics> {
345                    let #field_name = (#arg_expr,);
346                    let ( #(#destructuring,)* ) = self.fields;
347                    #builder_name {
348                        fields: ( #(#reconstructing,)* ),
349                        phantom: self.phantom,
350                    }
351                }
352            })
353        } else {
354            None
355        };
356
357        let strip_bool_fallback_method = if let Some((method_name, param_list, arg_expr)) = strip_bool_fallback {
358            Some(quote! {
359                #deprecated
360                #doc
361                #[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
362                pub fn #method_name (self, #param_list) -> #builder_name <#target_generics> {
363                    let #field_name = (#arg_expr,);
364                    let ( #(#destructuring,)* ) = self.fields;
365                    #builder_name {
366                        fields: ( #(#reconstructing,)* ),
367                        phantom: self.phantom,
368                    }
369                }
370            })
371        } else {
372            None
373        };
374
375        Ok(quote! {
376            #[allow(dead_code, non_camel_case_types, missing_docs)]
377            #[automatically_derived]
378            impl #impl_generics #builder_name <#ty_generics> #where_clause {
379                #deprecated
380                #doc
381                #[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
382                pub fn #method_name (self, #param_list) -> #builder_name <#target_generics> {
383                    let #field_name = (#arg_expr,);
384                    let ( #(#destructuring,)* ) = self.fields;
385                    #builder_name {
386                        fields: ( #(#reconstructing,)* ),
387                        phantom: self.phantom,
388                    }
389                }
390                #strip_option_fallback_method
391                #strip_bool_fallback_method
392            }
393            #[doc(hidden)]
394            #[allow(dead_code, non_camel_case_types, non_snake_case)]
395            #[allow(clippy::exhaustive_enums)]
396            pub enum #repeated_fields_error_type_name {}
397            #[doc(hidden)]
398            #[allow(dead_code, non_camel_case_types, missing_docs)]
399            #[automatically_derived]
400            impl #impl_generics #builder_name <#target_generics> #where_clause {
401                #[deprecated(
402                    note = #repeated_fields_error_message
403                )]
404                #doc
405                pub fn #method_name (self, _: #repeated_fields_error_type_name) -> #builder_name <#target_generics> {
406                    self
407                }
408            }
409        })
410    }
411
412    fn required_field_impl(&self, field: &FieldInfo) -> TokenStream {
413        let StructInfo { ref builder_name, .. } = self;
414
415        let FieldInfo {
416            name: ref field_name, ..
417        } = field;
418        let mut builder_generics: Vec<syn::GenericArgument> = self
419            .generics
420            .params
421            .iter()
422            .map(|generic_param| match generic_param {
423                syn::GenericParam::Type(type_param) => {
424                    let ident = type_param.ident.to_token_stream();
425                    syn::parse2(ident).unwrap()
426                }
427                syn::GenericParam::Lifetime(lifetime_def) => syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone()),
428                syn::GenericParam::Const(const_param) => {
429                    let ident = const_param.ident.to_token_stream();
430                    syn::parse2(ident).unwrap()
431                }
432            })
433            .collect();
434        let mut builder_generics_tuple = empty_type_tuple();
435        let generics = {
436            let mut generics = self.generics.clone();
437            for f in self.included_fields() {
438                if f.builder_attr.default.is_some() || f.builder_attr.via_mutators.is_some() {
439                    // `f` is not mandatory - it does not have its own fake `build` method, so `field` will need
440                    // to warn about missing `field` regardless of whether `f` is set.
441                    assert!(
442                        f.ordinal != field.ordinal,
443                        "`required_field_impl` called for optional field {}",
444                        field.name
445                    );
446                    generics.params.push(f.generic_ty_param());
447                    builder_generics_tuple.elems.push_value(f.type_ident());
448                } else if f.ordinal < field.ordinal {
449                    // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set,
450                    // `f`'s `build` method will warn, since it appears earlier in the argument list.
451                    builder_generics_tuple.elems.push_value(f.tuplized_type_ty_param());
452                } else if f.ordinal == field.ordinal {
453                    builder_generics_tuple.elems.push_value(empty_type());
454                } else {
455                    // `f` appears later in the argument list after `field`, so if they are both missing we will
456                    // show a warning for `field` and not for `f` - which means this warning should appear whether
457                    // or not `f` is set.
458                    generics.params.push(f.generic_ty_param());
459                    builder_generics_tuple.elems.push_value(f.type_ident());
460                }
461
462                builder_generics_tuple.elems.push_punct(Default::default());
463            }
464            generics
465        };
466
467        builder_generics.push(syn::GenericArgument::Type(builder_generics_tuple.into()));
468        let (impl_generics, _, where_clause) = generics.split_for_impl();
469
470        let early_build_error_type_name = syn::Ident::new(
471            &format!(
472                "{}_Error_Missing_required_field_{}",
473                builder_name,
474                strip_raw_ident_prefix(field_name.to_string())
475            ),
476            proc_macro2::Span::call_site(),
477        );
478        let early_build_error_message = format!("Missing required field {}", field_name);
479
480        let build_method_name = self.build_method_name();
481        let build_method_visibility = self.build_method_visibility();
482
483        quote! {
484            #[doc(hidden)]
485            #[allow(dead_code, non_camel_case_types, non_snake_case)]
486            #[allow(clippy::exhaustive_enums)]
487            pub enum #early_build_error_type_name {}
488            #[doc(hidden)]
489            #[allow(dead_code, non_camel_case_types, missing_docs, clippy::panic)]
490            #[automatically_derived]
491            impl #impl_generics #builder_name < #( #builder_generics ),* > #where_clause {
492                #[deprecated(
493                    note = #early_build_error_message
494                )]
495                #build_method_visibility fn #build_method_name(self, _: #early_build_error_type_name) -> ! {
496                    panic!()
497                }
498            }
499        }
500    }
501
502    fn mutator_impl(
503        &self,
504        mutator @ Mutator {
505            fun: mutator_fn,
506            required_fields,
507        }: &Mutator,
508    ) -> syn::Result<TokenStream> {
509        let StructInfo { ref builder_name, .. } = *self;
510
511        let mut required_fields = required_fields.clone();
512
513        let mut ty_generics = self.generic_arguments();
514        let mut destructuring = TokenStream::new();
515        let mut ty_generics_tuple = empty_type_tuple();
516        let mut generics = self.generics.clone();
517        let mut mutator_ty_fields = Punctuated::<_, Token![,]>::new();
518        let mut mutator_destructure_fields = Punctuated::<_, Token![,]>::new();
519        for f @ FieldInfo { name, ty, .. } in self.included_fields() {
520            if f.builder_attr.via_mutators.is_some() || required_fields.remove(f.name) {
521                ty_generics_tuple.elems.push(f.tuplized_type_ty_param());
522                mutator_ty_fields.push(quote!(#name: #ty));
523                mutator_destructure_fields.push(name);
524                quote!((#name,),).to_tokens(&mut destructuring);
525            } else {
526                generics.params.push(f.generic_ty_param());
527                let generic_argument: syn::Type = f.type_ident();
528                ty_generics_tuple.elems.push(generic_argument.clone());
529                quote!(#name,).to_tokens(&mut destructuring);
530            }
531        }
532        ty_generics.push(syn::GenericArgument::Type(ty_generics_tuple.into()));
533        let (impl_generics, _, where_clause) = generics.split_for_impl();
534
535        let mutator_struct_name = format_ident!("TypedBuilderFieldMutator");
536
537        let ItemFn { attrs, vis, .. } = mutator_fn;
538        let sig = mutator.outer_sig(parse_quote!(#builder_name <#ty_generics>));
539        let fn_name = &sig.ident;
540        let (_fn_impl_generics, fn_ty_generics, _fn_where_clause) = &sig.generics.split_for_impl();
541        let fn_call_turbofish = fn_ty_generics.as_turbofish();
542        let mutator_args = mutator.arguments();
543
544        // Generics for the mutator - should be similar to the struct's generics
545        let m_generics = &self.generics;
546        let (m_impl_generics, m_ty_generics, m_where_clause) = m_generics.split_for_impl();
547        let m_phantom = phantom_data_for_generics(self.generics);
548
549        Ok(quote! {
550            #[allow(dead_code, non_camel_case_types, missing_docs)]
551            #[automatically_derived]
552            impl #impl_generics #builder_name <#ty_generics> #where_clause {
553                #(#attrs)*
554                #[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
555                #vis #sig {
556                    struct #mutator_struct_name #m_generics #m_where_clause {
557                        __phantom: #m_phantom,
558                        #mutator_ty_fields
559                    }
560                    impl #m_impl_generics #mutator_struct_name #m_ty_generics #m_where_clause {
561                        #mutator_fn
562                    }
563
564                    let __args = (#mutator_args);
565
566                    let ( #destructuring ) = self.fields;
567                    let mut __mutator: #mutator_struct_name #m_ty_generics = #mutator_struct_name {
568                        __phantom: ::core::default::Default::default(),
569                        #mutator_destructure_fields
570                    };
571
572                    // This dance is required to keep mutator args and destrucutre fields from interfering.
573                    {
574                        let (#mutator_args) = __args;
575                        __mutator.#fn_name #fn_call_turbofish(#mutator_args);
576                    }
577
578                    let #mutator_struct_name {
579                        __phantom,
580                        #mutator_destructure_fields
581                    } = __mutator;
582
583                    #builder_name {
584                        fields: ( #destructuring ),
585                        phantom: self.phantom,
586                    }
587                }
588            }
589        })
590    }
591
592    fn build_method_name(&self) -> TokenStream {
593        self.builder_attr.build_method.common.get_name().unwrap_or(quote!(build))
594    }
595
596    fn build_method_visibility(&self) -> TokenStream {
597        first_visibility(&[self.builder_attr.build_method.common.vis.as_ref(), Some(&public_visibility())])
598    }
599
600    fn build_method_impl(&self) -> TokenStream {
601        let StructInfo {
602            ref name,
603            ref builder_name,
604            ..
605        } = *self;
606
607        let generics = {
608            let mut generics = self.generics.clone();
609            for field in self.included_fields() {
610                if field.builder_attr.default.is_some() {
611                    let trait_ref = syn::TraitBound {
612                        paren_token: None,
613                        lifetimes: None,
614                        modifier: syn::TraitBoundModifier::None,
615                        path: {
616                            let mut path = self.builder_attr.crate_module_path.clone();
617                            path.segments.push(syn::PathSegment {
618                                ident: Ident::new("Optional", Span::call_site()),
619                                arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
620                                    colon2_token: None,
621                                    lt_token: Default::default(),
622                                    args: [syn::GenericArgument::Type(field.ty.clone())].into_iter().collect(),
623                                    gt_token: Default::default(),
624                                }),
625                            });
626                            path
627                        },
628                    };
629                    let mut generic_param: syn::TypeParam = field.generic_ident.clone().into();
630                    generic_param.bounds.push(trait_ref.into());
631                    generics.params.push(generic_param.into());
632                }
633            }
634            generics
635        };
636        let (impl_generics, _, _) = generics.split_for_impl();
637
638        let (_, ty_generics, where_clause) = self.generics.split_for_impl();
639
640        let modified_ty_generics = modify_types_generics_hack(&ty_generics, |args| {
641            args.push(syn::GenericArgument::Type(
642                type_tuple(self.included_fields().map(|field| {
643                    if field.builder_attr.default.is_some() {
644                        field.type_ident()
645                    } else {
646                        field.tuplized_type_ty_param()
647                    }
648                }))
649                .into(),
650            ));
651        });
652
653        let destructuring = self.included_fields().map(|f| f.name);
654
655        // The default of a field can refer to earlier-defined fields, which we handle by
656        // writing out a bunch of `let` statements first, which can each refer to earlier ones.
657        // This means that field ordering may actually be significant, which isn't ideal. We could
658        // relax that restriction by calculating a DAG of field default dependencies and
659        // reordering based on that, but for now this much simpler thing is a reasonable approach.
660        let assignments = self.fields.iter().map(|field| {
661            let name = &field.name;
662
663            let maybe_mut = if let Some(span) = field.builder_attr.mutable_during_default_resolution {
664                quote_spanned!(span => mut)
665            } else {
666                quote!()
667            };
668
669            if let Some(ref default) = field.builder_attr.default {
670                if field.builder_attr.setter.skip.is_some() {
671                    quote!(let #maybe_mut #name = #default;)
672                } else {
673                    let crate_module_path = &self.builder_attr.crate_module_path;
674
675                    quote!(let #maybe_mut #name = #crate_module_path::Optional::into_value(#name, || #default);)
676                }
677            } else {
678                quote!(let #maybe_mut #name = #name.0;)
679            }
680        });
681        let field_names = self.fields.iter().map(|field| field.name);
682
683        let build_method_name = self.build_method_name();
684        let build_method_visibility = self.build_method_visibility();
685        let build_method_doc = if self.builder_attr.doc {
686            self.builder_attr
687                .build_method
688                .common
689                .get_doc_or(|| format!("Finalise the builder and create its [`{}`] instance", name))
690        } else {
691            quote!()
692        };
693
694        let type_constructor = {
695            let ty_generics = ty_generics.as_turbofish();
696            quote!(#name #ty_generics)
697        };
698
699        let (build_method_generic, output_type, build_method_where_clause) = match &self.builder_attr.build_method.into {
700            IntoSetting::NoConversion => (None, quote!(#name #ty_generics), None),
701            IntoSetting::GenericConversion => (
702                Some(quote!(<__R>)),
703                quote!(__R),
704                Some(quote!(where #name #ty_generics: Into<__R>)),
705            ),
706            IntoSetting::TypeConversionToSpecificType(into) => (None, into.to_token_stream(), None),
707        };
708
709        quote!(
710            #[allow(dead_code, non_camel_case_types, missing_docs)]
711            #[automatically_derived]
712            impl #impl_generics #builder_name #modified_ty_generics #where_clause {
713                #build_method_doc
714                #[allow(clippy::default_trait_access, clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
715                #build_method_visibility fn #build_method_name #build_method_generic (self) -> #output_type #build_method_where_clause {
716                    let ( #(#destructuring,)* ) = self.fields;
717                    #( #assignments )*
718
719                    #[allow(deprecated)]
720                    #type_constructor {
721                        #( #field_names ),*
722                    }.into()
723                }
724            }
725        )
726    }
727
728    pub fn derive(&self) -> syn::Result<TokenStream> {
729        let builder_creation = self.builder_creation_impl()?;
730        let fields = self
731            .setter_fields()
732            .map(|f| self.field_impl(f))
733            .collect::<Result<TokenStream, _>>()?;
734        let required_fields = self
735            .setter_fields()
736            .filter(|f| f.builder_attr.default.is_none())
737            .map(|f| self.required_field_impl(f));
738        let mutators = self
739            .fields
740            .iter()
741            .flat_map(|f| &f.builder_attr.mutators)
742            .chain(&self.builder_attr.mutators)
743            .map(|m| self.mutator_impl(m))
744            .collect::<Result<TokenStream, _>>()?;
745        let build_method = self.build_method_impl();
746
747        Ok(quote! {
748            #builder_creation
749            #fields
750            #(#required_fields)*
751            #mutators
752            #build_method
753        })
754    }
755}