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