darling_core/options/
input_field.rs
1use std::borrow::Cow;
2
3use syn::{parse_quote_spanned, spanned::Spanned};
4
5use crate::codegen;
6use crate::options::{Core, DefaultExpression, ParseAttribute};
7use crate::util::{Flag, SpannedValue};
8use crate::{Error, FromMeta, Result};
9
10#[derive(Debug, Clone)]
11pub 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 pub skip: Option<SpannedValue<bool>>,
21 pub post_transform: Option<codegen::PostfixTransform>,
22 pub multiple: Option<bool>,
23 pub flatten: Flag,
24}
25
26impl InputField {
27 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 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
62 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
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 fn with_inherited(mut self, parent: &Core) -> Self {
94 if self.attr_name.is_none() {
97 self.attr_name = Some(parent.rename_rule.apply_to_field(self.ident.to_string()));
98 }
99
100 self.default = match (&self.skip, self.default.is_some(), parent.default.is_some()) {
105 (_, true, _) => self.default,
107
108 (_, false, true) => Some(DefaultExpression::Inherit),
111
112 (Some(v), false, false) if **v => Some(DefaultExpression::Trait { span: v.span() }),
117
118 (_, false, false) => None,
120 };
121
122 self
123 }
124}
125
126impl ParseAttribute for InputField {
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}