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}
121