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