1use ident_case::RenameRule;
2
3use crate::ast::{Data, Fields, Style};
4use crate::codegen;
5use crate::codegen::PostfixTransform;
6use crate::error::Accumulator;
7use crate::options::{DefaultExpression, InputField, InputVariant, ParseAttribute, ParseData};
8use crate::{Error, FromMeta, Result};
9
10/// A struct or enum which should have `FromMeta` or `FromDeriveInput` implementations
11/// generated.
12#[derive(Debug, Clone)]
13pub struct Core {
14 /// The type identifier.
15 pub ident: syn::Ident,
16
17 /// The type's generics. If the type does not use any generics, this will
18 /// be an empty instance.
19 pub generics: syn::Generics,
20
21 /// Controls whether missing properties should cause errors or should be filled by
22 /// the result of a function call. This can be overridden at the field level.
23 pub default: Option<DefaultExpression>,
24
25 /// The rule that should be used to rename all fields/variants in the container.
26 pub rename_rule: RenameRule,
27
28 /// A transform which will be called on `darling::Result<Self>`. It must either be
29 /// an `FnOnce(T) -> T` when `map` is used, or `FnOnce(T) -> darling::Result<T>` when
30 /// `and_then` is used.
31 ///
32 /// `map` and `and_then` are mutually-exclusive to avoid confusion about the order in
33 /// which the two are applied.
34 pub post_transform: Option<codegen::PostfixTransform>,
35
36 /// The body of the _deriving_ type.
37 pub data: Data<InputVariant, InputField>,
38
39 /// The custom bound to apply to the generated impl
40 pub bound: Option<Vec<syn::WherePredicate>>,
41
42 /// Whether or not unknown fields should produce an error at compilation time.
43 pub allow_unknown_fields: Option<bool>,
44}
45
46impl Core {
47 /// Partially initializes `Core` by reading the identity, generics, and body shape.
48 pub fn start(di: &syn::DeriveInput) -> Result<Self> {
49 Ok(Core {
50 ident: di.ident.clone(),
51 generics: di.generics.clone(),
52 data: Data::try_empty_from(&di.data)?,
53 default: Default::default(),
54 // See https://github.com/TedDriggs/darling/issues/10: We default to snake_case
55 // for enums to help authors produce more idiomatic APIs.
56 rename_rule: if let syn::Data::Enum(_) = di.data {
57 RenameRule::SnakeCase
58 } else {
59 Default::default()
60 },
61 post_transform: Default::default(),
62 bound: Default::default(),
63 allow_unknown_fields: Default::default(),
64 })
65 }
66
67 fn as_codegen_default(&self) -> Option<codegen::DefaultExpression<'_>> {
68 self.default.as_ref().map(|expr| match *expr {
69 DefaultExpression::Explicit(ref path) => codegen::DefaultExpression::Explicit(path),
70 DefaultExpression::Inherit => {
71 // It should be impossible for any input to get here,
72 // so panic rather than returning an error or pretending
73 // everything is fine.
74 panic!("DefaultExpression::Inherit is not valid at container level")
75 }
76 DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span },
77 })
78 }
79}
80
81impl ParseAttribute for Core {
82 fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
83 let path = mi.path();
84
85 if path.is_ident("default") {
86 if self.default.is_some() {
87 return Err(Error::duplicate_field("default").with_span(mi));
88 }
89
90 self.default = FromMeta::from_meta(mi)?;
91 } else if path.is_ident("rename_all") {
92 // WARNING: This may have been set based on body shape previously,
93 // so an overwrite may be permissible.
94 self.rename_rule = FromMeta::from_meta(mi)?;
95 } else if path.is_ident("map") || path.is_ident("and_then") {
96 // This unwrap is safe because we just called is_ident above
97 let transformer = path.get_ident().unwrap().clone();
98
99 if let Some(post_transform) = &self.post_transform {
100 if transformer == post_transform.transformer {
101 return Err(Error::duplicate_field(&transformer.to_string()).with_span(mi));
102 } else {
103 return Err(Error::custom(format!(
104 "Options `{}` and `{}` are mutually exclusive",
105 transformer, post_transform.transformer
106 ))
107 .with_span(mi));
108 }
109 }
110
111 self.post_transform =
112 Some(PostfixTransform::new(transformer, FromMeta::from_meta(mi)?));
113 } else if path.is_ident("bound") {
114 self.bound = FromMeta::from_meta(mi)?;
115 } else if path.is_ident("allow_unknown_fields") {
116 if self.allow_unknown_fields.is_some() {
117 return Err(Error::duplicate_field("allow_unknown_fields").with_span(mi));
118 }
119
120 self.allow_unknown_fields = FromMeta::from_meta(mi)?;
121 } else {
122 return Err(Error::unknown_field_path(path).with_span(mi));
123 }
124
125 Ok(())
126 }
127}
128
129impl ParseData for Core {
130 fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
131 let v = InputVariant::from_variant(variant, Some(self))?;
132
133 match self.data {
134 Data::Enum(ref mut variants) => {
135 variants.push(v);
136 Ok(())
137 }
138 Data::Struct(_) => panic!("Core::parse_variant should never be called for a struct"),
139 }
140 }
141
142 fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
143 let f = InputField::from_field(field, Some(self))?;
144
145 match self.data {
146 Data::Struct(Fields {
147 style: Style::Unit, ..
148 }) => panic!("Core::parse_field should not be called on unit"),
149 Data::Struct(Fields { ref mut fields, .. }) => {
150 fields.push(f);
151 Ok(())
152 }
153 Data::Enum(_) => panic!("Core::parse_field should never be called for an enum"),
154 }
155 }
156
157 fn validate_body(&self, errors: &mut Accumulator) {
158 if let Data::Struct(fields) = &self.data {
159 let flatten_targets: Vec<_> = fields
160 .iter()
161 .filter_map(|field| {
162 if field.flatten.is_present() {
163 Some(field.flatten)
164 } else {
165 None
166 }
167 })
168 .collect();
169
170 if flatten_targets.len() > 1 {
171 for flatten in flatten_targets {
172 errors.push(
173 Error::custom("`#[darling(flatten)]` can only be applied to one field")
174 .with_span(&flatten.span()),
175 );
176 }
177 }
178 }
179 }
180}
181
182impl<'a> From<&'a Core> for codegen::TraitImpl<'a> {
183 fn from(v: &'a Core) -> Self {
184 codegen::TraitImpl {
185 ident: &v.ident,
186 generics: &v.generics,
187 data: v
188 .data
189 .as_ref()
190 .map_struct_fields(InputField::as_codegen_field)
191 .map_enum_variants(|variant: &InputVariant| variant.as_codegen_variant(&v.ident)),
192 default: v.as_codegen_default(),
193 post_transform: v.post_transform.as_ref(),
194 allow_unknown_fields: v.allow_unknown_fields.unwrap_or_default(),
195 }
196 }
197}
198