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::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 | } |
24 | |
25 | impl InputField { |
26 | /// Generate a view into this field that can be used for code generation. |
27 | pub fn as_codegen_field(&self) -> codegen::Field<'_> { |
28 | codegen::Field { |
29 | ident: &self.ident, |
30 | name_in_attr: self |
31 | .attr_name |
32 | .as_ref() |
33 | .map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed), |
34 | ty: &self.ty, |
35 | default_expression: self.as_codegen_default(), |
36 | with_path: self.with.as_ref().map_or_else( |
37 | || { |
38 | Cow::Owned( |
39 | parse_quote_spanned!(self.ty.span()=> ::darling::FromMeta::from_meta), |
40 | ) |
41 | }, |
42 | Cow::Borrowed, |
43 | ), |
44 | skip: *self.skip.unwrap_or_default(), |
45 | post_transform: self.post_transform.as_ref(), |
46 | multiple: self.multiple.unwrap_or_default(), |
47 | } |
48 | } |
49 | |
50 | /// Generate a codegen::DefaultExpression for this field. This requires the field name |
51 | /// in the `Inherit` case. |
52 | fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> { |
53 | self.default.as_ref().map(|expr| match *expr { |
54 | DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path), |
55 | DefaultExpression::Inherit => codegen::DefaultExpression::Inherit(&self.ident), |
56 | DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span }, |
57 | }) |
58 | } |
59 | |
60 | fn new(ident: syn::Ident, ty: syn::Type) -> Self { |
61 | InputField { |
62 | ident, |
63 | ty, |
64 | attr_name: None, |
65 | default: None, |
66 | with: None, |
67 | skip: None, |
68 | post_transform: Default::default(), |
69 | multiple: None, |
70 | } |
71 | } |
72 | |
73 | pub fn from_field(f: &syn::Field, parent: Option<&Core>) -> Result<Self> { |
74 | let ident = f |
75 | .ident |
76 | .clone() |
77 | .unwrap_or_else(|| syn::Ident::new("__unnamed" , ::proc_macro2::Span::call_site())); |
78 | let ty = f.ty.clone(); |
79 | let base = Self::new(ident, ty).parse_attributes(&f.attrs)?; |
80 | |
81 | Ok(if let Some(container) = parent { |
82 | base.with_inherited(container) |
83 | } else { |
84 | base |
85 | }) |
86 | } |
87 | |
88 | /// Apply inherited settings from the container. This is done _after_ parsing |
89 | /// to ensure deference to explicit field-level settings. |
90 | fn with_inherited(mut self, parent: &Core) -> Self { |
91 | // explicit renamings take precedence over rename rules on the container, |
92 | // but in the absence of an explicit name we apply the rule. |
93 | if self.attr_name.is_none() { |
94 | self.attr_name = Some(parent.rename_rule.apply_to_field(self.ident.to_string())); |
95 | } |
96 | |
97 | // Determine the default expression for this field, based on three pieces of information: |
98 | // 1. Will we look for this field in the attribute? |
99 | // 1. Is there a locally-defined default? |
100 | // 1. Did the parent define a default? |
101 | self.default = match (&self.skip, self.default.is_some(), parent.default.is_some()) { |
102 | // If we have a default, use it. |
103 | (_, true, _) => self.default, |
104 | |
105 | // If there isn't an explicit default but the struct sets a default, we'll |
106 | // inherit from that. |
107 | (_, false, true) => Some(DefaultExpression::Inherit), |
108 | |
109 | // If we're skipping the field and no defaults have been expressed then we should |
110 | // use the ::darling::export::Default trait, and set the span to the skip keyword |
111 | // so that an error caused by the skipped field's type not implementing `Default` |
112 | // will correctly identify why darling is trying to use `Default`. |
113 | (Some(v), false, false) if **v => Some(DefaultExpression::Trait { span: v.span() }), |
114 | |
115 | // If we don't have or need a default, then leave it blank. |
116 | (_, false, false) => None, |
117 | }; |
118 | |
119 | self |
120 | } |
121 | } |
122 | |
123 | impl ParseAttribute for InputField { |
124 | fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> { |
125 | let path = mi.path(); |
126 | |
127 | if path.is_ident("rename" ) { |
128 | if self.attr_name.is_some() { |
129 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
130 | } |
131 | |
132 | self.attr_name = FromMeta::from_meta(mi)?; |
133 | } else if path.is_ident("default" ) { |
134 | if self.default.is_some() { |
135 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
136 | } |
137 | self.default = FromMeta::from_meta(mi)?; |
138 | } else if path.is_ident("with" ) { |
139 | if self.with.is_some() { |
140 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
141 | } |
142 | |
143 | self.with = Some(FromMeta::from_meta(mi)?); |
144 | } else if path.is_ident("skip" ) { |
145 | if self.skip.is_some() { |
146 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
147 | } |
148 | |
149 | self.skip = FromMeta::from_meta(mi)?; |
150 | } else if path.is_ident("map" ) || path.is_ident("and_then" ) { |
151 | let transformer = path.get_ident().unwrap().clone(); |
152 | if let Some(post_transform) = &self.post_transform { |
153 | if transformer == post_transform.transformer { |
154 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
155 | } else { |
156 | return Err(Error::custom(format!( |
157 | "Options ` {}` and ` {}` are mutually exclusive" , |
158 | transformer, post_transform.transformer |
159 | )) |
160 | .with_span(mi)); |
161 | } |
162 | } |
163 | |
164 | self.post_transform = Some(codegen::PostfixTransform::new( |
165 | transformer, |
166 | FromMeta::from_meta(mi)?, |
167 | )); |
168 | } else if path.is_ident("multiple" ) { |
169 | if self.multiple.is_some() { |
170 | return Err(Error::duplicate_field_path(path).with_span(mi)); |
171 | } |
172 | |
173 | self.multiple = FromMeta::from_meta(mi)?; |
174 | } else { |
175 | return Err(Error::unknown_field_path(path).with_span(mi)); |
176 | } |
177 | |
178 | Ok(()) |
179 | } |
180 | } |
181 | |