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