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