derive_builder_core_fork_arti/
setter.rs

1#![allow(clippy::useless_let_if_seq)]
2use std::borrow::Cow;
3
4use proc_macro2::{Span, TokenStream};
5use quote::{ToTokens, TokenStreamExt};
6use syn;
7
8use BuilderFieldType;
9use BuilderPattern;
10use DeprecationNotes;
11use Each;
12
13/// Setter for the struct fields in the build method, implementing
14/// `quote::ToTokens`.
15///
16/// # Examples
17///
18/// Will expand to something like the following (depending on settings):
19///
20/// ```rust,ignore
21/// # extern crate proc_macro2;
22/// # #[macro_use]
23/// # extern crate quote;
24/// # extern crate syn;
25/// # #[macro_use]
26/// # extern crate derive_builder_core;
27/// # use derive_builder_core::{Setter, BuilderPattern};
28/// # fn main() {
29/// #     let mut setter = default_setter!();
30/// #     setter.pattern = BuilderPattern::Mutable;
31/// #
32/// #     assert_eq!(quote!(#setter).to_string(), quote!(
33/// # #[allow(unused_mut)]
34/// pub fn foo(&mut self, value: Foo) -> &mut Self {
35///     let mut new = self;
36///     new.foo = ::derive_builder::export::core::option::Option::Some(value);
37///     new
38/// }
39/// #     ).to_string());
40/// # }
41/// ```
42#[derive(Debug, Clone)]
43pub struct Setter<'a> {
44    /// Enables code generation for this setter fn.
45    pub setter_enabled: bool,
46    /// Enables code generation for the `try_` variant of this setter fn.
47    pub try_setter: bool,
48    /// Visibility of the setter, e.g. `syn::Visibility::Public`.
49    pub visibility: Cow<'a, syn::Visibility>,
50    /// How the setter method takes and returns `self` (e.g. mutably).
51    pub pattern: BuilderPattern,
52    /// Attributes which will be attached to this setter fn.
53    pub attrs: &'a [syn::Attribute],
54    /// Name of this setter fn.
55    pub ident: syn::Ident,
56    /// Name of the target field.
57    pub field_ident: &'a syn::Ident,
58    /// Type of the builder field.
59    ///
60    /// The corresonding builder field will be `Option<field_type>`.
61    pub field_type: BuilderFieldType<'a>,
62    /// Make the setter generic over `Into<T>`, where `T` is the field type.
63    pub generic_into: bool,
64    /// Make the setter remove the Option wrapper from the setter, remove the need to call Some(...).
65    /// when combined with into, the into is used on the content Type of the Option.
66    pub strip_option: bool,
67    /// Emit deprecation notes to the user.
68    pub deprecation_notes: &'a DeprecationNotes,
69    /// Emit extend method.
70    pub each: Option<&'a Each>,
71    /// Instead of providing a setter, provide an accessor
72    pub sub_accessor: bool,
73}
74
75impl<'a> ToTokens for Setter<'a> {
76    fn to_tokens(&self, tokens: &mut TokenStream) {
77        if self.setter_enabled {
78            let pattern = self.pattern;
79            let vis = &self.visibility;
80            let field_ident = self.field_ident;
81            let ident = &self.ident;
82            let attrs = self.attrs;
83            let deprecation_notes = self.deprecation_notes;
84
85            let self_param: TokenStream;
86            let return_ty: TokenStream;
87            let self_into_return_ty: TokenStream;
88
89            match pattern {
90                BuilderPattern::Owned => {
91                    self_param = quote!(self);
92                    return_ty = quote!(Self);
93                    self_into_return_ty = quote!(self);
94                }
95                BuilderPattern::Mutable => {
96                    self_param = quote!(&mut self);
97                    return_ty = quote!(&mut Self);
98                    self_into_return_ty = quote!(self);
99                }
100                BuilderPattern::Immutable => {
101                    self_param = quote!(&self);
102                    return_ty = quote!(Self);
103                    self_into_return_ty =
104                        quote!(::derive_builder::export::core::clone::Clone::clone(self));
105                }
106            };
107
108            let ty_params: TokenStream;
109            let param_ty: TokenStream;
110            let mut into_value: TokenStream;
111
112            let (field_type, builder_field_is_option) = self.field_type.setter_type_info();
113
114            let (ty, stripped_option) = {
115                if self.strip_option {
116                    match extract_type_from_option(field_type) {
117                        Some(ty) => (ty, true),
118                        None => (field_type, false),
119                    }
120                } else {
121                    (field_type, false)
122                }
123            };
124
125            if self.generic_into {
126                ty_params = quote!(<VALUE: ::derive_builder::export::core::convert::Into<#ty>>);
127                param_ty = quote!(VALUE);
128                into_value = quote!(value.into());
129            } else {
130                ty_params = quote!();
131                param_ty = quote!(#ty);
132                into_value = quote!(value);
133            }
134            // If both `stripped_option` and `builder_field_is_option`, the target field is `Option<field_type>`,
135            // the builder field is `Option<Option<field_type>>`, and the setter takes `file_type`, so we must wrap it twice.
136            if stripped_option {
137                into_value = wrap_expression_in_some(into_value);
138            }
139            if builder_field_is_option {
140                into_value = wrap_expression_in_some(into_value);
141            }
142
143            if self.sub_accessor {
144                // The accessor must take &mut self regardless of the pattern
145                // (although the option resolution code won't set sub_accessor other than with Mutable).
146                tokens.append_all(quote!(
147                    #(#attrs)*
148                    #vis fn #ident #ty_params (&mut self)
149                        -> &mut #param_ty
150                    {
151                        &mut self.#field_ident
152                    }
153                ));
154            } else {
155                tokens.append_all(quote!(
156                    #(#attrs)*
157                    #[allow(unused_mut)]
158                    #vis fn #ident #ty_params (#self_param, value: #param_ty)
159                        -> #return_ty
160                    {
161                        #deprecation_notes
162                        let mut new = #self_into_return_ty;
163                        new.#field_ident = #into_value;
164                        new
165                    }
166                ));
167            }
168
169            if self.try_setter {
170                let try_ty_params =
171                    quote!(<VALUE: ::derive_builder::export::core::convert::TryInto<#ty>>);
172                let try_ident = syn::Ident::new(&format!("try_{}", ident), Span::call_site());
173
174                let mut converted = quote! {converted};
175                if builder_field_is_option {
176                    converted = wrap_expression_in_some(converted);
177                }
178
179                tokens.append_all(quote!(
180                    #(#attrs)*
181                    #vis fn #try_ident #try_ty_params (#self_param, value: VALUE)
182                        -> ::derive_builder::export::core::result::Result<#return_ty, VALUE::Error>
183                    {
184                        let converted : #ty = value.try_into()?;
185                        let mut new = #self_into_return_ty;
186                        new.#field_ident = #converted;
187                        Ok(new)
188                    }
189                ));
190            }
191
192            if let Some(each) = self.each {
193                let ident_each = &each.name;
194
195                // Access the collection to extend, initialising with default value if necessary.
196                let get_initialized_collection = if stripped_option {
197                    // Outer (builder) Option -> Inner (field) Option -> collection.
198                    quote!(get_or_insert_with(|| Some(
199                        ::derive_builder::export::core::default::Default::default()
200                    ))
201                    .get_or_insert_with(::derive_builder::export::core::default::Default::default))
202                } else {
203                    // Outer (builder) Option -> collection.
204                    quote!(get_or_insert_with(
205                        ::derive_builder::export::core::default::Default::default
206                    ))
207                };
208
209                let ty_params: TokenStream;
210                let param_ty: TokenStream;
211                let into_item: TokenStream;
212
213                if each.into {
214                    ty_params = quote!(<VALUE, FROM_VALUE: ::derive_builder::export::core::convert::Into<VALUE>>);
215                    param_ty = quote!(FROM_VALUE);
216                    into_item = quote!(::derive_builder::export::core::convert::Into::into(item));
217                } else {
218                    ty_params = quote!(<VALUE>);
219                    param_ty = quote!(VALUE);
220                    into_item = quote!(item);
221                }
222
223                tokens.append_all(quote!(
224                    #(#attrs)*
225                    #[allow(unused_mut)]
226                    #vis fn #ident_each #ty_params(#self_param, item: #param_ty) -> #return_ty
227                    where
228                        #ty: ::derive_builder::export::core::default::Default + ::derive_builder::export::core::iter::Extend<VALUE>,
229                    {
230                        #deprecation_notes
231                        let mut new = #self_into_return_ty;
232                        new.#field_ident
233                            .#get_initialized_collection
234                            .extend(::derive_builder::export::core::option::Option::Some(#into_item));
235                        new
236                    }
237                ));
238            }
239        }
240    }
241}
242
243/// Returns expression wrapping `bare_value` in `Some`
244fn wrap_expression_in_some(bare_value: impl ToTokens) -> TokenStream {
245    quote!( ::derive_builder::export::core::option::Option::Some(#bare_value) )
246}
247
248// adapted from https://stackoverflow.com/a/55277337/469066
249// Note that since syn is a parser, it works with tokens.
250// We cannot know for sure that this is an Option.
251// The user could, for example, `type MaybeString = std::option::Option<String>`
252// We cannot handle those arbitrary names.
253fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
254    use syn::punctuated::Pair;
255    use syn::token::Colon2;
256    use syn::{GenericArgument, Path, PathArguments, PathSegment};
257
258    fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
259        match *ty {
260            syn::Type::Path(ref typepath) if typepath.qself.is_none() => Some(&typepath.path),
261            _ => None,
262        }
263    }
264
265    // TODO store (with lazy static) precomputed parsing of Option when support of rust 1.18 will be removed (incompatible with lazy_static)
266    // TODO maybe optimization, reverse the order of segments
267    fn extract_option_segment(path: &Path) -> Option<Pair<&PathSegment, &Colon2>> {
268        let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| {
269            acc.push_str(&v.ident.to_string());
270            acc.push('|');
271            acc
272        });
273        vec!["Option|", "std|option|Option|", "core|option|Option|"]
274            .into_iter()
275            .find(|s| idents_of_path == *s)
276            .and_then(|_| path.segments.last().map(Pair::End))
277    }
278
279    extract_type_path(ty)
280        .and_then(extract_option_segment)
281        .and_then(|pair_path_segment| {
282            let type_params = &pair_path_segment.into_value().arguments;
283            // It should have only on angle-bracketed param ("<String>"):
284            match *type_params {
285                PathArguments::AngleBracketed(ref params) => params.args.first(),
286                _ => None,
287            }
288        })
289        .and_then(|generic_arg| match *generic_arg {
290            GenericArgument::Type(ref ty) => Some(ty),
291            _ => None,
292        })
293}
294
295/// Helper macro for unit tests. This is _only_ public in order to be accessible
296/// from doc-tests too.
297#[doc(hidden)]
298#[macro_export]
299macro_rules! default_setter {
300    () => {
301        Setter {
302            setter_enabled: true,
303            try_setter: false,
304            visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)),
305            pattern: BuilderPattern::Mutable,
306            attrs: &vec![],
307            ident: syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
308            field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
309            field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(Foo)))),
310            generic_into: false,
311            strip_option: false,
312            deprecation_notes: &Default::default(),
313            each: None,
314            sub_accessor: false,
315        }
316    };
317}
318
319#[cfg(test)]
320mod tests {
321    #[allow(unused_imports)]
322    use super::*;
323
324    #[test]
325    fn immutable() {
326        let mut setter = default_setter!();
327        setter.pattern = BuilderPattern::Immutable;
328
329        assert_eq!(
330            quote!(#setter).to_string(),
331            quote!(
332                #[allow(unused_mut)]
333                pub fn foo(&self, value: Foo) -> Self {
334                    let mut new = ::derive_builder::export::core::clone::Clone::clone(self);
335                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
336                    new
337                }
338            )
339            .to_string()
340        );
341    }
342
343    #[test]
344    fn mutable() {
345        let mut setter = default_setter!();
346        setter.pattern = BuilderPattern::Mutable;
347
348        assert_eq!(
349            quote!(#setter).to_string(),
350            quote!(
351                #[allow(unused_mut)]
352                pub fn foo(&mut self, value: Foo) -> &mut Self {
353                    let mut new = self;
354                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
355                    new
356                }
357            )
358            .to_string()
359        );
360    }
361
362    #[test]
363    fn owned() {
364        let mut setter = default_setter!();
365        setter.pattern = BuilderPattern::Owned;
366
367        assert_eq!(
368            quote!(#setter).to_string(),
369            quote!(
370                #[allow(unused_mut)]
371                pub fn foo(self, value: Foo) -> Self {
372                    let mut new = self;
373                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
374                    new
375                }
376            )
377            .to_string()
378        );
379    }
380
381    #[test]
382    fn private() {
383        let vis = Cow::Owned(syn::Visibility::Inherited);
384
385        let mut setter = default_setter!();
386        setter.visibility = vis;
387
388        assert_eq!(
389            quote!(#setter).to_string(),
390            quote!(
391                #[allow(unused_mut)]
392                fn foo(&mut self, value: Foo) -> &mut Self {
393                    let mut new = self;
394                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
395                    new
396                }
397            )
398            .to_string()
399        );
400    }
401
402    #[test]
403    fn generic() {
404        let mut setter = default_setter!();
405        setter.generic_into = true;
406
407        #[rustfmt::skip]
408        assert_eq!(
409            quote!(#setter).to_string(),
410            quote!(
411                #[allow(unused_mut)]
412                pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
413                    &mut self,
414                    value: VALUE
415                ) -> &mut Self {
416                    let mut new = self;
417                    new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
418                    new
419                }
420            )
421            .to_string()
422        );
423    }
424
425    #[test]
426    fn strip_option() {
427        let ty = parse_quote!(Option<Foo>);
428        let mut setter = default_setter!();
429        setter.strip_option = true;
430        setter.field_type = BuilderFieldType::Optional(&ty);
431
432        #[rustfmt::skip]
433        assert_eq!(
434            quote!(#setter).to_string(),
435            quote!(
436                #[allow(unused_mut)]
437                pub fn foo(&mut self, value: Foo) -> &mut Self {
438                    let mut new = self;
439                    new.foo = ::derive_builder::export::core::option::Option::Some(
440                        ::derive_builder::export::core::option::Option::Some(value)
441                    );
442                    new
443                }
444            )
445            .to_string()
446        );
447    }
448
449    #[test]
450    fn strip_option_into() {
451        let ty = parse_quote!(Option<Foo>);
452        let mut setter = default_setter!();
453        setter.strip_option = true;
454        setter.generic_into = true;
455        setter.field_type = BuilderFieldType::Optional(&ty);
456
457        #[rustfmt::skip]
458        assert_eq!(
459            quote!(#setter).to_string(),
460            quote!(
461                #[allow(unused_mut)]
462                pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
463                    &mut self,
464                    value: VALUE
465                ) -> &mut Self {
466                    let mut new = self;
467                    new.foo = ::derive_builder::export::core::option::Option::Some(
468                        ::derive_builder::export::core::option::Option::Some(value.into())
469                    );
470                    new
471                }
472            )
473            .to_string()
474        );
475    }
476
477    // including try_setter
478    #[test]
479    fn full() {
480        //named!(outer_attrs -> Vec<syn::Attribute>, many0!(syn::Attribute::parse_outer));
481        //let attrs = outer_attrs.parse_str("#[some_attr]").unwrap();
482        let attrs: Vec<syn::Attribute> = vec![parse_quote!(#[some_attr])];
483
484        let mut deprecated = DeprecationNotes::default();
485        deprecated.push("Some example.".to_string());
486
487        let mut setter = default_setter!();
488        setter.attrs = attrs.as_slice();
489        setter.generic_into = true;
490        setter.deprecation_notes = &deprecated;
491        setter.try_setter = true;
492
493        assert_eq!(
494            quote!(#setter).to_string(),
495            quote!(
496            #[some_attr]
497            #[allow(unused_mut)]
498            pub fn foo <VALUE: ::derive_builder::export::core::convert::Into<Foo>>(&mut self, value: VALUE) -> &mut Self {
499                #deprecated
500                let mut new = self;
501                new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
502                new
503            }
504
505            #[some_attr]
506            pub fn try_foo<VALUE: ::derive_builder::export::core::convert::TryInto<Foo>>(&mut self, value: VALUE)
507                -> ::derive_builder::export::core::result::Result<&mut Self, VALUE::Error> {
508                let converted : Foo = value.try_into()?;
509                let mut new = self;
510                new.foo = ::derive_builder::export::core::option::Option::Some(converted);
511                Ok(new)
512            }
513        ).to_string()
514        );
515    }
516
517    #[test]
518    fn no_std() {
519        let mut setter = default_setter!();
520        setter.pattern = BuilderPattern::Immutable;
521
522        assert_eq!(
523            quote!(#setter).to_string(),
524            quote!(
525                #[allow(unused_mut)]
526                pub fn foo(&self, value: Foo) -> Self {
527                    let mut new = ::derive_builder::export::core::clone::Clone::clone(self);
528                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
529                    new
530                }
531            )
532            .to_string()
533        );
534    }
535
536    #[test]
537    fn no_std_generic() {
538        let mut setter = default_setter!();
539        setter.generic_into = true;
540
541        #[rustfmt::skip]
542        assert_eq!(
543            quote!(#setter).to_string(),
544            quote!(
545                #[allow(unused_mut)]
546                pub fn foo<VALUE: ::derive_builder::export::core::convert::Into<Foo>>(
547                    &mut self,
548                    value: VALUE
549                ) -> &mut Self {
550                    let mut new = self;
551                    new.foo = ::derive_builder::export::core::option::Option::Some(value.into());
552                    new
553                }
554            )
555            .to_string()
556        );
557    }
558
559    #[test]
560    fn setter_disabled() {
561        let mut setter = default_setter!();
562        setter.setter_enabled = false;
563
564        assert_eq!(quote!(#setter).to_string(), quote!().to_string());
565    }
566
567    #[test]
568    fn try_setter() {
569        let mut setter: Setter = default_setter!();
570        setter.pattern = BuilderPattern::Mutable;
571        setter.try_setter = true;
572
573        #[rustfmt::skip]
574        assert_eq!(
575            quote!(#setter).to_string(),
576            quote!(
577                #[allow(unused_mut)]
578                pub fn foo(&mut self, value: Foo) -> &mut Self {
579                    let mut new = self;
580                    new.foo = ::derive_builder::export::core::option::Option::Some(value);
581                    new
582                }
583
584                pub fn try_foo<VALUE: ::derive_builder::export::core::convert::TryInto<Foo>>(
585                    &mut self,
586                    value: VALUE
587                ) -> ::derive_builder::export::core::result::Result<&mut Self, VALUE::Error> {
588                    let converted: Foo = value.try_into()?;
589                    let mut new = self;
590                    new.foo = ::derive_builder::export::core::option::Option::Some(converted);
591                    Ok(new)
592                }
593            )
594            .to_string()
595        );
596    }
597
598    #[test]
599    fn extract_type_from_option_on_simple_type() {
600        let ty_foo = parse_quote!(Foo);
601        assert_eq!(extract_type_from_option(&ty_foo), None);
602
603        for s in vec![
604            parse_quote!(Option<Foo>),
605            parse_quote!(std::option::Option<Foo>),
606            parse_quote!(::std::option::Option<Foo>),
607            parse_quote!(core::option::Option<Foo>),
608            parse_quote!(::core::option::Option<Foo>),
609        ] {
610            assert_eq!(extract_type_from_option(&s), Some(&ty_foo));
611        }
612    }
613}