1 use std::borrow::Cow; 2 3 use syn::{parse_quote_spanned, spanned::Spanned}; 4 5 use crate::codegen; 6 use crate::options::{Core, DefaultExpression, ParseAttribute}; 7 use crate::util::{Flag, SpannedValue}; 8 use crate::{Error, FromMeta, Result}; 9 10 #[derive(Debug, Clone)] 11 pub struct InputField { 12 pub ident: syn::Ident, 13 pub attr_name: Option<String>, 14 pub ty: syn::Type, 15 pub default: Option<DefaultExpression>, 16 pub with: Option<syn::Path>, 17 18 /// If `true`, generated code will not look for this field in the input meta item, 19 /// instead always falling back to either `InputField::default` or `Default::default`. 20 pub skip: Option<SpannedValue<bool>>, 21 pub post_transform: Option<codegen::PostfixTransform>, 22 pub multiple: Option<bool>, 23 pub flatten: Flag, 24 } 25 26 impl InputField { 27 /// Generate a view into this field that can be used for code generation. as_codegen_field(&self) -> codegen::Field<'_>28 pub fn as_codegen_field(&self) -> codegen::Field<'_> { 29 codegen::Field { 30 ident: &self.ident, 31 name_in_attr: self 32 .attr_name 33 .as_ref() 34 .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed), 35 ty: &self.ty, 36 default_expression: self.as_codegen_default(), 37 with_path: self.with.as_ref().map_or_else( 38 || { 39 Cow::Owned( 40 parse_quote_spanned!(self.ty.span()=> ::darling::FromMeta::from_meta), 41 ) 42 }, 43 Cow::Borrowed, 44 ), 45 skip: *self.skip.unwrap_or_default(), 46 post_transform: self.post_transform.as_ref(), 47 multiple: self.multiple.unwrap_or_default(), 48 flatten: self.flatten.is_present(), 49 } 50 } 51 52 /// Generate a codegen::DefaultExpression for this field. This requires the field name 53 /// in the `Inherit` case. as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>>54 fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> { 55 self.default.as_ref().map(|expr| match *expr { 56 DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path), 57 DefaultExpression::Inherit => codegen::DefaultExpression::Inherit(&self.ident), 58 DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span }, 59 }) 60 } 61 new(ident: syn::Ident, ty: syn::Type) -> Self62 fn new(ident: syn::Ident, ty: syn::Type) -> Self { 63 InputField { 64 ident, 65 ty, 66 attr_name: None, 67 default: None, 68 with: None, 69 skip: None, 70 post_transform: Default::default(), 71 multiple: None, 72 flatten: Default::default(), 73 } 74 } 75 from_field(f: &syn::Field, parent: Option<&Core>) -> Result<Self>76 pub fn from_field(f: &syn::Field, parent: Option<&Core>) -> Result<Self> { 77 let ident = f 78 .ident 79 .clone() 80 .unwrap_or_else(|| syn::Ident::new("__unnamed", ::proc_macro2::Span::call_site())); 81 let ty = f.ty.clone(); 82 let base = Self::new(ident, ty).parse_attributes(&f.attrs)?; 83 84 Ok(if let Some(container) = parent { 85 base.with_inherited(container) 86 } else { 87 base 88 }) 89 } 90 91 /// Apply inherited settings from the container. This is done _after_ parsing 92 /// to ensure deference to explicit field-level settings. with_inherited(mut self, parent: &Core) -> Self93 fn with_inherited(mut self, parent: &Core) -> Self { 94 // explicit renamings take precedence over rename rules on the container, 95 // but in the absence of an explicit name we apply the rule. 96 if self.attr_name.is_none() { 97 self.attr_name = Some(parent.rename_rule.apply_to_field(self.ident.to_string())); 98 } 99 100 // Determine the default expression for this field, based on three pieces of information: 101 // 1. Will we look for this field in the attribute? 102 // 1. Is there a locally-defined default? 103 // 1. Did the parent define a default? 104 self.default = match (&self.skip, self.default.is_some(), parent.default.is_some()) { 105 // If we have a default, use it. 106 (_, true, _) => self.default, 107 108 // If there isn't an explicit default but the struct sets a default, we'll 109 // inherit from that. 110 (_, false, true) => Some(DefaultExpression::Inherit), 111 112 // If we're skipping the field and no defaults have been expressed then we should 113 // use the ::darling::export::Default trait, and set the span to the skip keyword 114 // so that an error caused by the skipped field's type not implementing `Default` 115 // will correctly identify why darling is trying to use `Default`. 116 (Some(v), false, false) if **v => Some(DefaultExpression::Trait { span: v.span() }), 117 118 // If we don't have or need a default, then leave it blank. 119 (_, false, false) => None, 120 }; 121 122 self 123 } 124 } 125 126 impl ParseAttribute for InputField { parse_nested(&mut self, mi: &syn::Meta) -> Result<()>127 fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { 128 let path = mi.path(); 129 130 if path.is_ident("rename") { 131 if self.attr_name.is_some() { 132 return Err(Error::duplicate_field_path(path).with_span(mi)); 133 } 134 135 self.attr_name = FromMeta::from_meta(mi)?; 136 137 if self.flatten.is_present() { 138 return Err( 139 Error::custom("`flatten` and `rename` cannot be used together").with_span(mi), 140 ); 141 } 142 } else if path.is_ident("default") { 143 if self.default.is_some() { 144 return Err(Error::duplicate_field_path(path).with_span(mi)); 145 } 146 self.default = FromMeta::from_meta(mi)?; 147 } else if path.is_ident("with") { 148 if self.with.is_some() { 149 return Err(Error::duplicate_field_path(path).with_span(mi)); 150 } 151 152 self.with = Some(FromMeta::from_meta(mi)?); 153 154 if self.flatten.is_present() { 155 return Err( 156 Error::custom("`flatten` and `with` cannot be used together").with_span(mi), 157 ); 158 } 159 } else if path.is_ident("skip") { 160 if self.skip.is_some() { 161 return Err(Error::duplicate_field_path(path).with_span(mi)); 162 } 163 164 self.skip = FromMeta::from_meta(mi)?; 165 166 if self.skip.map(|v| *v).unwrap_or_default() && self.flatten.is_present() { 167 return Err( 168 Error::custom("`flatten` and `skip` cannot be used together").with_span(mi), 169 ); 170 } 171 } else if path.is_ident("map") || path.is_ident("and_then") { 172 let transformer = path.get_ident().unwrap().clone(); 173 if let Some(post_transform) = &self.post_transform { 174 if transformer == post_transform.transformer { 175 return Err(Error::duplicate_field_path(path).with_span(mi)); 176 } else { 177 return Err(Error::custom(format!( 178 "Options `{}` and `{}` are mutually exclusive", 179 transformer, post_transform.transformer 180 )) 181 .with_span(mi)); 182 } 183 } 184 185 self.post_transform = Some(codegen::PostfixTransform::new( 186 transformer, 187 FromMeta::from_meta(mi)?, 188 )); 189 } else if path.is_ident("multiple") { 190 if self.multiple.is_some() { 191 return Err(Error::duplicate_field_path(path).with_span(mi)); 192 } 193 194 self.multiple = FromMeta::from_meta(mi)?; 195 196 if self.multiple == Some(true) && self.flatten.is_present() { 197 return Err( 198 Error::custom("`flatten` and `multiple` cannot be used together").with_span(mi), 199 ); 200 } 201 } else if path.is_ident("flatten") { 202 if self.flatten.is_present() { 203 return Err(Error::duplicate_field_path(path).with_span(mi)); 204 } 205 206 self.flatten = FromMeta::from_meta(mi)?; 207 208 let mut conflicts = Error::accumulator(); 209 210 if self.multiple == Some(true) { 211 conflicts.push( 212 Error::custom("`flatten` and `multiple` cannot be used together").with_span(mi), 213 ); 214 } 215 216 if self.attr_name.is_some() { 217 conflicts.push( 218 Error::custom("`flatten` and `rename` cannot be used together").with_span(mi), 219 ); 220 } 221 222 if self.with.is_some() { 223 conflicts.push( 224 Error::custom("`flatten` and `with` cannot be used together").with_span(mi), 225 ); 226 } 227 228 if self.skip.map(|v| *v).unwrap_or_default() { 229 conflicts.push( 230 Error::custom("`flatten` and `skip` cannot be used together").with_span(mi), 231 ); 232 } 233 234 conflicts.finish()?; 235 } else { 236 return Err(Error::unknown_field_path(path).with_span(mi)); 237 } 238 239 Ok(()) 240 } 241 } 242