derive_builder_core_fork_arti/
builder.rs1use std::borrow::Cow;
2
3use proc_macro2::TokenStream;
4use quote::{format_ident, ToTokens, TokenStreamExt};
5use syn::punctuated::Punctuated;
6use syn::{self, Path, TraitBound, TraitBoundModifier, TypeParamBound};
7
8use doc_comment_from;
9use BuildMethod;
10use BuilderField;
11use BuilderPattern;
12use DeprecationNotes;
13use Setter;
14
15#[derive(Debug)]
88pub struct Builder<'a> {
89 pub enabled: bool,
91 pub ident: syn::Ident,
93 pub pattern: BuilderPattern,
95 pub derives: &'a [Path],
97 pub struct_attrs: &'a [syn::Attribute],
99 pub impl_attrs: &'a [syn::Attribute],
101 pub impl_default: bool,
105 pub create_empty: syn::Ident,
111 pub generics: Option<&'a syn::Generics>,
114 pub visibility: Cow<'a, syn::Visibility>,
116 pub fields: Vec<TokenStream>,
120 pub field_initializers: Vec<TokenStream>,
124 pub functions: Vec<TokenStream>,
126 pub generate_error: bool,
130 pub must_derive_clone: bool,
135 pub doc_comment: Option<syn::Attribute>,
137 pub deprecation_notes: DeprecationNotes,
139 pub std: bool,
141}
142
143impl<'a> ToTokens for Builder<'a> {
144 fn to_tokens(&self, tokens: &mut TokenStream) {
145 if self.enabled {
146 let builder_vis = &self.visibility;
147 let builder_ident = &self.ident;
148 let bounded_generics = self.compute_impl_bounds();
149 let (impl_generics, _, _) = bounded_generics.split_for_impl();
150 let (struct_generics, ty_generics, where_clause) = self
151 .generics
152 .map(syn::Generics::split_for_impl)
153 .map(|(i, t, w)| (Some(i), Some(t), Some(w)))
154 .unwrap_or((None, None, None));
155 let builder_fields = &self.fields;
156 let builder_field_initializers = &self.field_initializers;
157 let create_empty = &self.create_empty;
158 let functions = &self.functions;
159
160 let derive_attr = {
162 let clone_trait: Path = parse_quote!(Clone);
163
164 let mut traits: Punctuated<&Path, Token![,]> = Default::default();
165 if self.must_derive_clone {
166 traits.push(&clone_trait);
167 }
168 traits.extend(self.derives);
169
170 if traits.is_empty() {
171 quote!()
172 } else {
173 quote!(#[derive(#traits)])
174 }
175 };
176
177 let struct_attrs = self.struct_attrs;
178 let impl_attrs = self.impl_attrs;
179
180 let builder_doc_comment = &self.doc_comment;
181 let deprecation_notes = &self.deprecation_notes.as_item();
182
183 #[cfg(not(feature = "clippy"))]
184 tokens.append_all(quote!(#[allow(clippy::all)]));
185
186 tokens.append_all(quote!(
190 #derive_attr
191 #(#struct_attrs)*
192 #builder_doc_comment
193 #builder_vis struct #builder_ident #struct_generics #where_clause {
194 #(#builder_fields)*
195 }
196 ));
197
198 #[cfg(not(feature = "clippy"))]
199 tokens.append_all(quote!(#[allow(clippy::all)]));
200
201 tokens.append_all(quote!(
202 #(#impl_attrs)*
203 #[allow(dead_code)]
204 impl #impl_generics #builder_ident #ty_generics #where_clause {
205 #(#functions)*
206 #deprecation_notes
207
208 fn #create_empty() -> Self {
210 Self {
211 #(#builder_field_initializers)*
212 }
213 }
214 }
215 ));
216
217 if self.impl_default {
218 tokens.append_all(quote!(
219 impl #impl_generics ::derive_builder::export::core::default::Default for #builder_ident #ty_generics #where_clause {
220 fn default() -> Self {
221 Self::#create_empty()
222 }
223 }
224 ));
225 }
226
227 if self.generate_error {
228 let builder_error_ident = format_ident!("{}Error", builder_ident);
229 let builder_error_doc = format!("Error type for {}", builder_ident);
230
231 tokens.append_all(quote!(
232 #[doc=#builder_error_doc]
233 #[derive(Debug)]
234 #[non_exhaustive]
235 #builder_vis enum #builder_error_ident {
236 UninitializedField(&'static str),
238 ValidationError(::derive_builder::export::core::string::String),
240 }
241
242 impl ::derive_builder::export::core::convert::From<::derive_builder::UninitializedFieldError> for #builder_error_ident {
243 fn from(s: ::derive_builder::UninitializedFieldError) -> Self {
244 Self::UninitializedField(s.field_name())
245 }
246 }
247
248 impl ::derive_builder::export::core::convert::From<::derive_builder::export::core::string::String> for #builder_error_ident {
249 fn from(s: ::derive_builder::export::core::string::String) -> Self {
250 Self::ValidationError(s)
251 }
252 }
253
254 impl ::derive_builder::export::core::fmt::Display for #builder_error_ident {
255 fn fmt(&self, f: &mut ::derive_builder::export::core::fmt::Formatter) -> ::derive_builder::export::core::fmt::Result {
256 match self {
257 Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field),
258 Self::ValidationError(ref error) => write!(f, "{}", error),
259 }
260 }
261 }
262 ));
263
264 if self.std {
265 tokens.append_all(quote!(
266 impl std::error::Error for #builder_error_ident {}
267
268 impl<E: std::error::Error> ::derive_builder::export::core::convert::From<::derive_builder::SubfieldBuildError<E>> for #builder_error_ident {
269 fn from(e: ::derive_builder::SubfieldBuildError<E>) -> Self {
270 Self::ValidationError(::derive_builder::export::core::string::ToString::to_string(&e))
271 }
272 }
273 ));
274 }
275 }
276 }
277 }
278}
279
280impl<'a> Builder<'a> {
281 pub fn doc_comment(&mut self, s: String) -> &mut Self {
283 self.doc_comment = Some(doc_comment_from(s));
284 self
285 }
286
287 pub fn push_field(&mut self, f: BuilderField) -> &mut Self {
289 self.fields.push(quote!(#f));
290 self.field_initializers.push(f.default_initializer_tokens());
291 self
292 }
293
294 pub fn push_setter_fn(&mut self, f: Setter) -> &mut Self {
296 self.functions.push(quote!(#f));
297 self
298 }
299
300 pub fn push_build_fn(&mut self, f: BuildMethod) -> &mut Self {
302 self.functions.push(quote!(#f));
303 self
304 }
305
306 fn compute_impl_bounds(&self) -> syn::Generics {
311 if let Some(type_gen) = self.generics {
312 let mut generics = type_gen.clone();
313
314 if !self.pattern.requires_clone() || type_gen.type_params().next().is_none() {
315 return generics;
316 }
317
318 let clone_bound = TypeParamBound::Trait(TraitBound {
319 paren_token: None,
320 modifier: TraitBoundModifier::None,
321 lifetimes: None,
322 path: syn::parse_quote!(::derive_builder::export::core::clone::Clone),
323 });
324
325 for typ in generics.type_params_mut() {
326 typ.bounds.push(clone_bound.clone());
327 }
328
329 generics
330 } else {
331 Default::default()
332 }
333 }
334}
335
336#[doc(hidden)]
339#[macro_export]
340macro_rules! default_builder {
341 () => {
342 Builder {
343 enabled: true,
344 ident: syn::Ident::new("FooBuilder", ::proc_macro2::Span::call_site()),
345 pattern: Default::default(),
346 derives: &vec![],
347 struct_attrs: &vec![],
348 impl_attrs: &vec![],
349 impl_default: true,
350 create_empty: syn::Ident::new("create_empty", ::proc_macro2::Span::call_site()),
351 generics: None,
352 visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)),
353 fields: vec![quote!(foo: u32,)],
354 field_initializers: vec![quote!(foo: ::derive_builder::export::core::default::Default::default(), )],
355 functions: vec![quote!(fn bar() -> { unimplemented!() })],
356 generate_error: true,
357 must_derive_clone: true,
358 doc_comment: None,
359 deprecation_notes: DeprecationNotes::default(),
360 std: true,
361 }
362 };
363}
364
365#[cfg(test)]
366mod tests {
367 #[allow(unused_imports)]
368 use super::*;
369 use proc_macro2::TokenStream;
370 use syn::Ident;
371
372 fn add_generated_error(result: &mut TokenStream) {
373 result.append_all(quote!(
374 #[doc="Error type for FooBuilder"]
375 #[derive(Debug)]
376 #[non_exhaustive]
377 pub enum FooBuilderError {
378 UninitializedField(&'static str),
380 ValidationError(::derive_builder::export::core::string::String),
382 }
383
384 impl ::derive_builder::export::core::convert::From<::derive_builder::UninitializedFieldError> for FooBuilderError {
385 fn from(s: ::derive_builder::UninitializedFieldError) -> Self {
386 Self::UninitializedField(s.field_name())
387 }
388 }
389
390 impl ::derive_builder::export::core::convert::From<::derive_builder::export::core::string::String> for FooBuilderError {
391 fn from(s: ::derive_builder::export::core::string::String) -> Self {
392 Self::ValidationError(s)
393 }
394 }
395
396 impl ::derive_builder::export::core::fmt::Display for FooBuilderError {
397 fn fmt(&self, f: &mut ::derive_builder::export::core::fmt::Formatter) -> ::derive_builder::export::core::fmt::Result {
398 match self {
399 Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field),
400 Self::ValidationError(ref error) => write!(f, "{}", error),
401 }
402 }
403 }
404
405 impl std::error::Error for FooBuilderError {}
406
407 impl<E: std::error::Error> ::derive_builder::export::core::convert::From<::derive_builder::SubfieldBuildError<E>> for FooBuilderError {
408 fn from(e: ::derive_builder::SubfieldBuildError<E>) -> Self {
409 Self::ValidationError(::derive_builder::export::core::string::ToString::to_string(&e))
410 }
411 }
412 ));
413 }
414
415 #[test]
416 fn simple() {
417 let builder = default_builder!();
418
419 assert_eq!(
420 quote!(#builder).to_string(),
421 {
422 let mut result = quote!();
423
424 #[cfg(not(feature = "clippy"))]
425 result.append_all(quote!(#[allow(clippy::all)]));
426
427 result.append_all(quote!(
428 #[derive(Clone)]
429 pub struct FooBuilder {
430 foo: u32,
431 }
432 ));
433
434 #[cfg(not(feature = "clippy"))]
435 result.append_all(quote!(#[allow(clippy::all)]));
436
437 result.append_all(quote!(
438 #[allow(dead_code)]
439 impl FooBuilder {
440 fn bar () -> {
441 unimplemented!()
442 }
443
444 fn create_empty() -> Self {
446 Self {
447 foo: ::derive_builder::export::core::default::Default::default(),
448 }
449 }
450 }
451
452 impl ::derive_builder::export::core::default::Default for FooBuilder {
453 fn default() -> Self {
454 Self::create_empty()
455 }
456 }
457 ));
458
459 add_generated_error(&mut result);
460
461 result
462 }
463 .to_string()
464 );
465 }
466
467 #[test]
468 fn rename_create_empty() {
469 let mut builder = default_builder!();
470 builder.create_empty = Ident::new("empty", proc_macro2::Span::call_site());
471
472 assert_eq!(
473 quote!(#builder).to_string(),
474 {
475 let mut result = quote!();
476
477 #[cfg(not(feature = "clippy"))]
478 result.append_all(quote!(#[allow(clippy::all)]));
479
480 result.append_all(quote!(
481 #[derive(Clone)]
482 pub struct FooBuilder {
483 foo: u32,
484 }
485 ));
486
487 #[cfg(not(feature = "clippy"))]
488 result.append_all(quote!(#[allow(clippy::all)]));
489
490 result.append_all(quote!(
491 #[allow(dead_code)]
492 impl FooBuilder {
493 fn bar () -> {
494 unimplemented!()
495 }
496
497 fn empty() -> Self {
499 Self {
500 foo: ::derive_builder::export::core::default::Default::default(),
501 }
502 }
503 }
504
505 impl ::derive_builder::export::core::default::Default for FooBuilder {
506 fn default() -> Self {
507 Self::empty()
508 }
509 }
510 ));
511
512 add_generated_error(&mut result);
513
514 result
515 }
516 .to_string()
517 );
518 }
519
520 #[rustfmt::skip]
523 #[test]
524 fn generic() {
525 let ast: syn::DeriveInput = parse_quote! {
526 struct Lorem<'a, T: Debug> where T: PartialEq { }
527 };
528 let generics = ast.generics;
529 let mut builder = default_builder!();
530 builder.generics = Some(&generics);
531
532 assert_eq!(
533 quote!(#builder).to_string(),
534 {
535 let mut result = quote!();
536
537 #[cfg(not(feature = "clippy"))]
538 result.append_all(quote!(#[allow(clippy::all)]));
539
540 result.append_all(quote!(
541 #[derive(Clone)]
542 pub struct FooBuilder<'a, T: Debug> where T: PartialEq {
543 foo: u32,
544 }
545 ));
546
547 #[cfg(not(feature = "clippy"))]
548 result.append_all(quote!(#[allow(clippy::all)]));
549
550 result.append_all(quote!(
551 #[allow(dead_code)]
552 impl<'a, T: Debug + ::derive_builder::export::core::clone::Clone> FooBuilder<'a, T> where T: PartialEq {
553 fn bar() -> {
554 unimplemented!()
555 }
556
557 fn create_empty() -> Self {
559 Self {
560 foo: ::derive_builder::export::core::default::Default::default(),
561 }
562 }
563 }
564
565 impl<'a, T: Debug + ::derive_builder::export::core::clone::Clone> ::derive_builder::export::core::default::Default for FooBuilder<'a, T> where T: PartialEq {
566 fn default() -> Self {
567 Self::create_empty()
568 }
569 }
570 ));
571
572 add_generated_error(&mut result);
573
574 result
575 }.to_string()
576 );
577 }
578
579 #[rustfmt::skip]
582 #[test]
583 fn generic_reference() {
584 let ast: syn::DeriveInput = parse_quote! {
585 struct Lorem<'a, T: 'a + Default> where T: PartialEq{ }
586 };
587
588 let generics = ast.generics;
589 let mut builder = default_builder!();
590 builder.generics = Some(&generics);
591
592 assert_eq!(
593 quote!(#builder).to_string(),
594 {
595 let mut result = quote!();
596
597 #[cfg(not(feature = "clippy"))]
598 result.append_all(quote!(#[allow(clippy::all)]));
599
600 result.append_all(quote!(
601 #[derive(Clone)]
602 pub struct FooBuilder<'a, T: 'a + Default> where T: PartialEq {
603 foo: u32,
604 }
605 ));
606
607 #[cfg(not(feature = "clippy"))]
608 result.append_all(quote!(#[allow(clippy::all)]));
609
610 result.append_all(quote!(
611 #[allow(dead_code)]
612 impl<'a, T: 'a + Default + ::derive_builder::export::core::clone::Clone> FooBuilder<'a, T>
613 where
614 T: PartialEq
615 {
616 fn bar() -> {
617 unimplemented!()
618 }
619
620 fn create_empty() -> Self {
622 Self {
623 foo: ::derive_builder::export::core::default::Default::default(),
624 }
625 }
626 }
627
628 impl<'a, T: 'a + Default + ::derive_builder::export::core::clone::Clone> ::derive_builder::export::core::default::Default for FooBuilder<'a, T> where T: PartialEq {
629 fn default() -> Self {
630 Self::create_empty()
631 }
632 }
633 ));
634
635 add_generated_error(&mut result);
636
637 result
638 }.to_string()
639 );
640 }
641
642 #[rustfmt::skip]
645 #[test]
646 fn owned_generic() {
647 let ast: syn::DeriveInput = parse_quote! {
648 struct Lorem<'a, T: Debug> where T: PartialEq { }
649 };
650 let generics = ast.generics;
651 let mut builder = default_builder!();
652 builder.generics = Some(&generics);
653 builder.pattern = BuilderPattern::Owned;
654 builder.must_derive_clone = false;
655
656 assert_eq!(
657 quote!(#builder).to_string(),
658 {
659 let mut result = quote!();
660
661 #[cfg(not(feature = "clippy"))]
662 result.append_all(quote!(#[allow(clippy::all)]));
663
664 result.append_all(quote!(
665 pub struct FooBuilder<'a, T: Debug> where T: PartialEq {
666 foo: u32,
667 }
668 ));
669
670 #[cfg(not(feature = "clippy"))]
671 result.append_all(quote!(#[allow(clippy::all)]));
672
673 result.append_all(quote!(
674 #[allow(dead_code)]
675 impl<'a, T: Debug> FooBuilder<'a, T> where T: PartialEq {
676 fn bar() -> {
677 unimplemented!()
678 }
679
680 fn create_empty() -> Self {
682 Self {
683 foo: ::derive_builder::export::core::default::Default::default(),
684 }
685 }
686 }
687
688 impl<'a, T: Debug> ::derive_builder::export::core::default::Default for FooBuilder<'a, T>
689 where T: PartialEq {
690 fn default() -> Self {
691 Self::create_empty()
692 }
693 }
694 ));
695
696 add_generated_error(&mut result);
697
698 result
699 }.to_string()
700 );
701 }
702
703 #[test]
704 fn disabled() {
705 let mut builder = default_builder!();
706 builder.enabled = false;
707
708 assert_eq!(quote!(#builder).to_string(), quote!().to_string());
709 }
710
711 #[test]
712 fn add_derives() {
713 let derives = vec![parse_quote!(Serialize)];
714 let mut builder = default_builder!();
715 builder.derives = &derives;
716
717 assert_eq!(
718 quote!(#builder).to_string(),
719 {
720 let mut result = quote!();
721
722 #[cfg(not(feature = "clippy"))]
723 result.append_all(quote!(#[allow(clippy::all)]));
724
725 result.append_all(quote!(
726 #[derive(Clone, Serialize)]
727 pub struct FooBuilder {
728 foo: u32,
729 }
730 ));
731
732 #[cfg(not(feature = "clippy"))]
733 result.append_all(quote!(#[allow(clippy::all)]));
734
735 result.append_all(quote!(
736 #[allow(dead_code)]
737 impl FooBuilder {
738 fn bar () -> {
739 unimplemented!()
740 }
741
742 fn create_empty() -> Self {
744 Self {
745 foo: ::derive_builder::export::core::default::Default::default(),
746 }
747 }
748 }
749
750 impl ::derive_builder::export::core::default::Default for FooBuilder {
751 fn default() -> Self {
752 Self::create_empty()
753 }
754 }
755 ));
756
757 add_generated_error(&mut result);
758
759 result
760 }
761 .to_string()
762 );
763 }
764}