Skip to main content

darling_core/options/
core.rs

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 callable) => {
70                codegen::DefaultExpression::Explicit(callable)
71            }
72            DefaultExpression::Inherit => {
73                // It should be impossible for any input to get here,
74                // so panic rather than returning an error or pretending
75                // everything is fine.
76                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            // WARNING: This may have been set based on body shape previously,
95            // so an overwrite may be permissible.
96            self.rename_rule = FromMeta::from_meta(mi)?;
97        } else if path.is_ident("map") || path.is_ident("and_then") {
98            // This unwrap is safe because we just called is_ident above
99            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}