derive_builder_core_fork_arti/
builder_field.rs

1use std::borrow::Cow;
2
3use proc_macro2::TokenStream;
4use quote::{ToTokens, TokenStreamExt};
5use syn;
6
7/// Field for the builder struct, implementing `quote::ToTokens`.
8///
9/// # Examples
10///
11/// Will expand to something like the following (depending on settings):
12///
13/// ```rust,ignore
14/// # extern crate proc_macro2;
15/// # #[macro_use]
16/// # extern crate quote;
17/// # #[macro_use]
18/// # extern crate syn;
19/// # #[macro_use]
20/// # extern crate derive_builder_core;
21/// # use derive_builder_core::{BuilderField, BuilderPattern};
22/// # fn main() {
23/// #    let attrs = vec![parse_quote!(#[some_attr])];
24/// #    let mut field = default_builder_field!();
25/// #    field.attrs = attrs.as_slice();
26/// #
27/// #    assert_eq!(quote!(#field).to_string(), quote!(
28/// #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
29/// #    ).to_string());
30/// # }
31/// ```
32#[derive(Debug, Clone)]
33pub struct BuilderField<'a> {
34    /// Name of the target field.
35    pub field_ident: &'a syn::Ident,
36    /// Type of the builder field.
37    pub field_type: BuilderFieldType<'a>,
38    /// Visibility of this builder field, e.g. `syn::Visibility::Public`.
39    pub field_visibility: Cow<'a, syn::Visibility>,
40    /// Attributes which will be attached to this builder field.
41    pub attrs: &'a [syn::Attribute],
42}
43
44impl<'a> ToTokens for BuilderField<'a> {
45    fn to_tokens(&self, tokens: &mut TokenStream) {
46        let ident = self.field_ident;
47        let vis = &self.field_visibility;
48        let ty = &self.field_type;
49        let attrs = self.attrs;
50        tokens.append_all(quote!(
51            #(#attrs)* #vis #ident: #ty,
52        ));
53    }
54}
55
56impl<'a> BuilderField<'a> {
57    /// Emits a struct field initializer that initializes the field to `Default::default`.
58    pub fn default_initializer_tokens(&self) -> TokenStream {
59        let ident = self.field_ident;
60        quote! { #ident : ::derive_builder::export::core::default::Default::default(), }
61    }
62}
63
64/// The type of a field in the builder struct
65#[derive(Debug, Clone)]
66pub enum BuilderFieldType<'a> {
67    /// The corresonding builder field will be `Option<field_type>`.
68    Optional(&'a syn::Type),
69    /// The corresponding builder field will be just this type
70    Precise(&'a syn::Type),
71    /// The corresponding builder field will be a PhantomData
72    ///
73    /// We do this if if the field is disabled.  We mustn't just completely omit the field from the builder:
74    /// if we did that, the builder might have unused generic parameters (since we copy the generics from
75    /// the target struct).   Using a PhantomData of the original field type provides the right generic usage
76    /// (and the right variance).  The alternative would be to give the user a way to separately control
77    /// the generics of the builder struct, which would be very awkward to use and complex to document.
78    /// We could just include the field anyway, as `Option<T>`, but this is wasteful of space, and it
79    /// seems good to explicitly suppress the existence of a variable that won't be set or read.
80    Phantom(&'a syn::Type),
81}
82
83impl<'a> BuilderFieldType<'a> {
84    /// Obtain type information for the builder field setter
85    ///
86    /// Return value:
87    ///  * `.0`: type of the argument to the setter function
88    ///          (before application of `strip_option`, `into`)
89    ///  * `.1`: whether the builder field is `Option<type>` rather than just `type`
90    pub fn setter_type_info(&'a self) -> (&'a syn::Type, bool) {
91        match self {
92            BuilderFieldType::Optional(ty) => (ty, true),
93            BuilderFieldType::Precise(ty) => (ty, false),
94            BuilderFieldType::Phantom(_ty) => panic!("phantom fields should never have setters"),
95        }
96    }
97}
98
99impl<'a> ToTokens for BuilderFieldType<'a> {
100    fn to_tokens(&self, tokens: &mut TokenStream) {
101        match self {
102            BuilderFieldType::Optional(ty) => tokens.append_all(quote!(
103                ::derive_builder::export::core::option::Option<#ty>
104            )),
105            BuilderFieldType::Precise(ty) => ty.to_tokens(tokens),
106            BuilderFieldType::Phantom(ty) => tokens.append_all(quote!(
107                ::derive_builder::export::core::marker::PhantomData<#ty>
108            )),
109        }
110    }
111}
112
113/// Helper macro for unit tests. This is _only_ public in order to be accessible
114/// from doc-tests too.
115#[cfg(test)] // This contains a Box::leak, so is suitable only for tests
116#[doc(hidden)]
117#[macro_export]
118macro_rules! default_builder_field {
119    () => {{
120        BuilderField {
121            field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()),
122            field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(String)))),
123            field_visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)),
124            attrs: &[parse_quote!(#[some_attr])],
125        }
126    }};
127}
128
129#[cfg(test)]
130mod tests {
131    #[allow(unused_imports)]
132    use super::*;
133
134    #[test]
135    fn setter_enabled() {
136        let field = default_builder_field!();
137
138        assert_eq!(
139            quote!(#field).to_string(),
140            quote!(
141                #[some_attr] pub foo: ::derive_builder::export::core::option::Option<String>,
142            )
143            .to_string()
144        );
145    }
146
147    #[test]
148    fn setter_disabled() {
149        let mut field = default_builder_field!();
150        field.field_visibility = Cow::Owned(syn::Visibility::Inherited);
151        field.field_type = match field.field_type {
152            BuilderFieldType::Optional(ty) => BuilderFieldType::Phantom(ty),
153            _ => panic!(),
154        };
155
156        assert_eq!(
157            quote!(#field).to_string(),
158            quote!(
159                #[some_attr]
160                foo: ::derive_builder::export::core::marker::PhantomData<String>,
161            )
162            .to_string()
163        );
164    }
165
166    #[test]
167    fn private_field() {
168        let private = Cow::Owned(syn::Visibility::Inherited);
169        let mut field = default_builder_field!();
170        field.field_visibility = private;
171
172        assert_eq!(
173            quote!(#field).to_string(),
174            quote!(
175                #[some_attr]
176                foo: ::derive_builder::export::core::option::Option<String>,
177            )
178            .to_string()
179        );
180    }
181}