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