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 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 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 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 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 {
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 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}