1 | use proc_macro2; |
2 | |
3 | use ast; |
4 | use attr; |
5 | use syn; |
6 | use utils; |
7 | |
8 | /// Derive `Default` for `input`. |
9 | pub 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 | "e!(#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("e!(#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`. |
114 | fn 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 | } |
121 | |