1 use proc_macro2::TokenStream; 2 use quote::quote; 3 4 use crate::ast::{Fields, Style}; 5 use crate::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 crate::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 crate::codegen) fn core_loop(&self) -> TokenStream { 37 let arms = self.fields.as_ref().map(Field::as_match); 38 // If there is a flatten field, buffer the unknown field so it can be passed 39 // to the flatten function with all other unknown fields. 40 let handle_unknown = if self.fields.iter().any(|f| f.flatten) { 41 quote! { 42 __flatten.push(::darling::ast::NestedMeta::Meta(__inner.clone())); 43 } 44 } 45 // If we're allowing unknown fields, then handling one is a no-op. 46 else if self.allow_unknown_fields { 47 quote!() 48 } 49 // Otherwise, we're going to push a new spanned error pointing at the field. 50 else { 51 let mut names = self.fields.iter().filter_map(Field::as_name).peekable(); 52 // We can't call `unknown_field_with_alts` with an empty slice, or else it fails to 53 // infer the type of the slice item. 54 let err_fn = if names.peek().is_none() { 55 quote!(unknown_field(__other)) 56 } else { 57 quote!(unknown_field_with_alts(__other, &[#(#names),*])) 58 }; 59 60 quote! { 61 __errors.push(::darling::Error::#err_fn.with_span(__inner)); 62 } 63 }; 64 let arms = arms.iter(); 65 66 quote!( 67 for __item in __items { 68 match *__item { 69 ::darling::export::NestedMeta::Meta(ref __inner) => { 70 let __name = ::darling::util::path_to_string(__inner.path()); 71 match __name.as_str() { 72 #(#arms)* 73 __other => { #handle_unknown } 74 } 75 } 76 ::darling::export::NestedMeta::Lit(ref __inner) => { 77 __errors.push(::darling::Error::unsupported_format("literal") 78 .with_span(__inner)); 79 } 80 } 81 } 82 ) 83 } 84 require_fields(&self) -> TokenStream85 pub fn require_fields(&self) -> TokenStream { 86 match *self.fields { 87 Fields { 88 style: Style::Struct, 89 ref fields, 90 .. 91 } => { 92 let checks = fields.iter().map(Field::as_presence_check); 93 quote!(#(#checks)*) 94 } 95 _ => panic!("FieldsGen doesn't support tuples for requirement checks"), 96 } 97 } 98 initializers(&self) -> TokenStream99 pub(in crate::codegen) fn initializers(&self) -> TokenStream { 100 let inits = self.fields.as_ref().map(Field::as_initializer); 101 let inits = inits.iter(); 102 103 quote!(#(#inits),*) 104 } 105 } 106