darling_core/options/
core.rs1use 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#[derive(Debug, Clone)]
13pub struct Core {
14 pub ident: syn::Ident,
16
17 pub generics: syn::Generics,
20
21 pub default: Option<DefaultExpression>,
24
25 pub rename_rule: RenameRule,
27
28 pub post_transform: Option<codegen::PostfixTransform>,
35
36 pub data: Data<InputVariant, InputField>,
38
39 pub bound: Option<Vec<syn::WherePredicate>>,
41
42 pub allow_unknown_fields: Option<bool>,
44}
45
46impl Core {
47 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 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 callable) => {
70 codegen::DefaultExpression::Explicit(callable)
71 }
72 DefaultExpression::Inherit => {
73 panic!("DefaultExpression::Inherit is not valid at container level")
77 }
78 DefaultExpression::Trait { span } => codegen::DefaultExpression::Trait { span },
79 })
80 }
81}
82
83impl ParseAttribute for Core {
84 fn parse_nested(&mut self, mi: &syn::Meta) -> Result<()> {
85 let path = mi.path();
86
87 if path.is_ident("default") {
88 if self.default.is_some() {
89 return Err(Error::duplicate_field("default").with_span(mi));
90 }
91
92 self.default = FromMeta::from_meta(mi)?;
93 } else if path.is_ident("rename_all") {
94 self.rename_rule = FromMeta::from_meta(mi)?;
97 } else if path.is_ident("map") || path.is_ident("and_then") {
98 let transformer = path.get_ident().unwrap().clone();
100
101 if let Some(post_transform) = &self.post_transform {
102 if transformer == post_transform.transformer {
103 return Err(Error::duplicate_field(&transformer.to_string()).with_span(mi));
104 } else {
105 return Err(Error::custom(format!(
106 "Options `{}` and `{}` are mutually exclusive",
107 transformer, post_transform.transformer
108 ))
109 .with_span(mi));
110 }
111 }
112
113 self.post_transform =
114 Some(PostfixTransform::new(transformer, FromMeta::from_meta(mi)?));
115 } else if path.is_ident("bound") {
116 self.bound = FromMeta::from_meta(mi)?;
117 } else if path.is_ident("allow_unknown_fields") {
118 if self.allow_unknown_fields.is_some() {
119 return Err(Error::duplicate_field("allow_unknown_fields").with_span(mi));
120 }
121
122 self.allow_unknown_fields = FromMeta::from_meta(mi)?;
123 } else {
124 return Err(Error::unknown_field_path(path).with_span(mi));
125 }
126
127 Ok(())
128 }
129}
130
131impl ParseData for Core {
132 fn parse_variant(&mut self, variant: &syn::Variant) -> Result<()> {
133 let v = InputVariant::from_variant(variant, Some(self))?;
134
135 match self.data {
136 Data::Enum(ref mut variants) => {
137 variants.push(v);
138 Ok(())
139 }
140 Data::Struct(_) => panic!("Core::parse_variant should never be called for a struct"),
141 }
142 }
143
144 fn parse_field(&mut self, field: &syn::Field) -> Result<()> {
145 let f = InputField::from_field(field, Some(self))?;
146
147 match self.data {
148 Data::Struct(Fields {
149 style: Style::Unit, ..
150 }) => panic!("Core::parse_field should not be called on unit"),
151 Data::Struct(Fields { ref mut fields, .. }) => {
152 fields.push(f);
153 Ok(())
154 }
155 Data::Enum(_) => panic!("Core::parse_field should never be called for an enum"),
156 }
157 }
158
159 fn validate_body(&self, errors: &mut Accumulator) {
160 if let Data::Struct(fields) = &self.data {
161 let flatten_targets: Vec<_> = fields
162 .iter()
163 .filter_map(|field| {
164 if field.flatten.is_present() {
165 Some(field.flatten)
166 } else {
167 None
168 }
169 })
170 .collect();
171
172 if flatten_targets.len() > 1 {
173 for flatten in flatten_targets {
174 errors.push(
175 Error::custom("`#[darling(flatten)]` can only be applied to one field")
176 .with_span(&flatten.span()),
177 );
178 }
179 }
180 }
181 }
182}
183
184impl<'a> From<&'a Core> for codegen::TraitImpl<'a> {
185 fn from(v: &'a Core) -> Self {
186 codegen::TraitImpl {
187 ident: &v.ident,
188 generics: &v.generics,
189 data: v
190 .data
191 .as_ref()
192 .map_struct_fields(InputField::as_codegen_field)
193 .map_enum_variants(|variant| variant.as_codegen_variant(&v.ident)),
194 default: v.as_codegen_default(),
195 post_transform: v.post_transform.as_ref(),
196 allow_unknown_fields: v.allow_unknown_fields.unwrap_or_default(),
197 }
198 }
199}