1 use proc_macro2::TokenStream;
2 
3 use ast::Fields;
4 use ast::Style;
5 use codegen::Field;
6 
7 pub struct FieldsGen<'a> {
8     fields: &'a Fields<Field<'a>>,
9     allow_unknown_fields: bool,
10 }
11 
12 impl<'a> FieldsGen<'a> {
new(fields: &'a Fields<Field<'a>>, allow_unknown_fields: bool) -> Self13     pub fn new(fields: &'a Fields<Field<'a>>, allow_unknown_fields: bool) -> Self {
14         Self {
15             fields,
16             allow_unknown_fields,
17         }
18     }
19 
20     /// Create declarations for all the fields in the struct.
declarations(&self) -> TokenStream21     pub(in codegen) fn declarations(&self) -> TokenStream {
22         match *self.fields {
23             Fields {
24                 style: Style::Struct,
25                 ref fields,
26                 ..
27             } => {
28                 let vdr = fields.iter().map(Field::as_declaration);
29                 quote!(#(#vdr)*)
30             }
31             _ => panic!("FieldsGen doesn't support tuples yet"),
32         }
33     }
34 
35     /// Generate the loop which walks meta items looking for property matches.
core_loop(&self) -> TokenStream36     pub(in codegen) fn core_loop(&self) -> TokenStream {
37         let arms = self.fields.as_ref().map(Field::as_match);
38 
39         // If we're allowing unknown fields, then handling one is a no-op.
40         // Otherwise, we're going to push a new spanned error pointing at the field.
41         let handle_unknown = if self.allow_unknown_fields {
42             quote!()
43         } else {
44             // We can't call `unknown_field_with_alts` with an empty slice, or else it fails to
45             // infer the type of the slice item.
46             let err_fn = if arms.is_empty() {
47                 quote!(unknown_field(__other))
48             } else {
49                 let names = self.fields.as_ref().map(Field::as_name);
50                 let names = names.iter();
51                 quote!(unknown_field_with_alts(__other, &[#(#names),*]))
52             };
53 
54             quote! {
55                 __errors.push(::darling::Error::#err_fn.with_span(__inner));
56             }
57         };
58         let arms = arms.iter();
59 
60         quote!(
61             for __item in __items {
62                 if let ::syn::NestedMeta::Meta(ref __inner) = *__item {
63                     let __name = __inner.path().segments.iter().map(|s| s.ident.to_string()).collect::<Vec<String>>().join("::");
64                     match __name.as_str() {
65                         #(#arms)*
66                         __other => { #handle_unknown }
67                     }
68                 }
69             }
70         )
71     }
72 
require_fields(&self) -> TokenStream73     pub fn require_fields(&self) -> TokenStream {
74         match *self.fields {
75             Fields {
76                 style: Style::Struct,
77                 ref fields,
78                 ..
79             } => {
80                 let checks = fields.iter().map(Field::as_presence_check);
81                 quote!(#(#checks)*)
82             }
83             _ => panic!("FieldsGen doesn't support tuples for requirement checks"),
84         }
85     }
86 
initializers(&self) -> TokenStream87     pub(in codegen) fn initializers(&self) -> TokenStream {
88         let inits = self.fields.as_ref().map(Field::as_initializer);
89         let inits = inits.iter();
90 
91         quote!(#(#inits),*)
92     }
93 }
94