derivative/
default.rs

1use proc_macro2;
2
3use ast;
4use attr;
5use syn;
6use utils;
7
8/// Derive `Default` for `input`.
9pub fn derive(input: &ast::Input, default: &attr::InputDefault) -> proc_macro2::TokenStream {
10    fn make_variant_data(
11        variant_name: &proc_macro2::TokenStream,
12        style: ast::Style,
13        fields: &[ast::Field],
14    ) -> proc_macro2::TokenStream {
15        let default_trait_path = default_trait_path();
16
17        match style {
18            ast::Style::Struct => {
19                let mut defaults = Vec::new();
20
21                for f in fields {
22                    let name = f
23                        .ident
24                        .as_ref()
25                        .expect("A structure field must have a name");
26                    let default = f
27                        .attrs
28                        .default_value()
29                        .map_or_else(|| quote!(#default_trait_path::default()), |v| quote!(#v));
30
31                    defaults.push(quote!(#name: #default));
32                }
33
34                quote!(#variant_name { #(#defaults),* })
35            }
36            ast::Style::Tuple => {
37                let mut defaults = Vec::new();
38
39                for f in fields {
40                    let default = f
41                        .attrs
42                        .default_value()
43                        .map_or_else(|| quote!(#default_trait_path::default()), |v| quote!(#v));
44
45                    defaults.push(default);
46                }
47
48                quote!(#variant_name ( #(#defaults),* ))
49            }
50            ast::Style::Unit => quote!(#variant_name),
51        }
52    }
53
54    let name = &input.ident;
55    let default_trait_path = default_trait_path();
56    let generics = utils::build_impl_generics(
57        input,
58        &default_trait_path,
59        |attrs| attrs.default_bound().is_none(),
60        |field| field.default_bound(),
61        |input| input.default_bound(),
62    );
63    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
64
65    let body = match input.body {
66        ast::Body::Enum(ref data) => {
67            let arms = data.iter().filter_map(|variant| {
68                if variant.attrs.default.is_some() {
69                    let vname = &variant.ident;
70
71                    Some(make_variant_data(
72                        &quote!(#name::#vname),
73                        variant.style,
74                        &variant.fields,
75                    ))
76                } else {
77                    None
78                }
79            });
80
81            quote!(#(#arms),*)
82        }
83        ast::Body::Struct(style, ref vd) => make_variant_data(&quote!(#name), style, vd),
84    };
85
86    let new_fn = if default.new {
87        Some(quote!(
88            #[allow(unused_qualifications)]
89            impl #impl_generics #name #ty_generics #where_clause {
90                /// Creates a default value for this type.
91                #[inline]
92                pub fn new() -> Self {
93                    <Self as #default_trait_path>::default()
94                }
95            }
96        ))
97    } else {
98        None
99    };
100
101    quote!(
102        #new_fn
103
104        #[allow(unused_qualifications)]
105        impl #impl_generics #default_trait_path for #name #ty_generics #where_clause {
106            fn default() -> Self {
107                #body
108            }
109        }
110    )
111}
112
113/// Return the path of the `Default` trait, that is `::std::default::Default`.
114fn default_trait_path() -> syn::Path {
115    if cfg!(feature = "use_core") {
116        parse_quote!(::core::default::Default)
117    } else {
118        parse_quote!(::std::default::Default)
119    }
120}