Skip to main content

darling_core/ast/data/
mod.rs

1use std::{slice, vec};
2
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, quote_spanned, ToTokens};
5use syn::spanned::Spanned;
6
7use crate::usage::{
8    self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams,
9};
10use crate::{Error, FromField, FromVariant, Result};
11
12pub use nested_meta::{MetaNameValueInvalidExpr, NestedMeta};
13
14mod nested_meta;
15
16/// A struct or enum body.
17///
18/// `V` is the type which receives any encountered variants, and `F` receives struct fields.
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum Data<V, F> {
21    Enum(Vec<V>),
22    Struct(Fields<F>),
23}
24
25impl<V, F> Data<V, F> {
26    /// Creates an empty body of the same shape as the passed-in body.
27    ///
28    /// # Panics
29    /// This function will panic if passed `syn::Data::Union`.
30    pub fn empty_from(src: &syn::Data) -> Self {
31        match *src {
32            syn::Data::Enum(_) => Data::Enum(vec![]),
33            syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)),
34            syn::Data::Union(_) => panic!("Unions are not supported"),
35        }
36    }
37
38    /// Creates an empty body of the same shape as the passed-in body.
39    ///
40    /// `darling` does not support unions; calling this function with a union body will return an error.
41    pub fn try_empty_from(src: &syn::Data) -> Result<Self> {
42        match *src {
43            syn::Data::Enum(_) => Ok(Data::Enum(vec![])),
44            syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))),
45            // This deliberately doesn't set a span on the error message, as the error is most useful if
46            // applied to the call site of the offending macro. Given that the message is very generic,
47            // putting it on the union keyword ends up being confusing.
48            syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
49        }
50    }
51
52    /// Creates a new `Data<&'a V, &'a F>` instance from `Data<V, F>`.
53    pub fn as_ref(&self) -> Data<&V, &F> {
54        match *self {
55            Data::Enum(ref variants) => Data::Enum(variants.iter().collect()),
56            Data::Struct(ref data) => Data::Struct(data.as_ref()),
57        }
58    }
59
60    /// Applies a function `V -> U` on enum variants, if this is an enum.
61    pub fn map_enum_variants<T, U>(self, map: T) -> Data<U, F>
62    where
63        T: FnMut(V) -> U,
64    {
65        match self {
66            Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()),
67            Data::Struct(f) => Data::Struct(f),
68        }
69    }
70
71    /// Applies a function `F -> U` on struct fields, if this is a struct.
72    pub fn map_struct_fields<T, U>(self, map: T) -> Data<V, U>
73    where
74        T: FnMut(F) -> U,
75    {
76        match self {
77            Data::Enum(v) => Data::Enum(v),
78            Data::Struct(f) => Data::Struct(f.map(map)),
79        }
80    }
81
82    /// Applies a function to the `Fields` if this is a struct.
83    pub fn map_struct<T, U>(self, mut map: T) -> Data<V, U>
84    where
85        T: FnMut(Fields<F>) -> Fields<U>,
86    {
87        match self {
88            Data::Enum(v) => Data::Enum(v),
89            Data::Struct(f) => Data::Struct(map(f)),
90        }
91    }
92
93    /// Consumes the `Data`, returning `Fields<F>` if it was a struct.
94    pub fn take_struct(self) -> Option<Fields<F>> {
95        match self {
96            Data::Enum(_) => None,
97            Data::Struct(f) => Some(f),
98        }
99    }
100
101    /// Consumes the `Data`, returning `Vec<V>` if it was an enum.
102    pub fn take_enum(self) -> Option<Vec<V>> {
103        match self {
104            Data::Enum(v) => Some(v),
105            Data::Struct(_) => None,
106        }
107    }
108
109    /// Returns the fields if `Data` is a struct.
110    pub fn as_struct(&self) -> Option<&Fields<F>> {
111        match self {
112            Data::Enum(_) => None,
113            Data::Struct(f) => Some(f),
114        }
115    }
116
117    /// Returns the variants if `Data` is an enum.
118    pub fn as_enum(&self) -> Option<&[V]> {
119        match self {
120            Data::Enum(v) => Some(v),
121            Data::Struct(_) => None,
122        }
123    }
124
125    /// Returns `true` if this instance is `Data::Enum`.
126    pub fn is_enum(&self) -> bool {
127        match *self {
128            Data::Enum(_) => true,
129            Data::Struct(_) => false,
130        }
131    }
132
133    /// Returns `true` if this instance is `Data::Struct`.
134    pub fn is_struct(&self) -> bool {
135        !self.is_enum()
136    }
137}
138
139impl<V: FromVariant, F: FromField> Data<V, F> {
140    /// Attempt to convert from a `syn::Data` instance.
141    pub fn try_from(body: &syn::Data) -> Result<Self> {
142        match *body {
143            syn::Data::Enum(ref data) => {
144                let mut errors = Error::accumulator();
145                let items = data
146                    .variants
147                    .iter()
148                    .filter_map(|v| errors.handle(FromVariant::from_variant(v)))
149                    .collect();
150
151                errors.finish_with(Data::Enum(items))
152            }
153            syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
154            // This deliberately doesn't set a span on the error message, as the error is most useful if
155            // applied to the call site of the offending macro. Given that the message is very generic,
156            // putting it on the union keyword ends up being confusing.
157            syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
158        }
159    }
160}
161
162impl<'a, V: FromVariant, F: FromField> TryFrom<&'a syn::Data> for Data<V, F> {
163    type Error = Error;
164
165    fn try_from(value: &'a syn::Data) -> Result<Self> {
166        Data::try_from(value)
167    }
168}
169
170impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
171    fn uses_type_params<'a>(
172        &self,
173        options: &usage::Options,
174        type_set: &'a IdentSet,
175    ) -> IdentRefSet<'a> {
176        match *self {
177            Data::Struct(ref v) => v.uses_type_params(options, type_set),
178            Data::Enum(ref v) => v.uses_type_params(options, type_set),
179        }
180    }
181}
182
183impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
184    fn uses_lifetimes<'a>(
185        &self,
186        options: &usage::Options,
187        lifetimes: &'a LifetimeSet,
188    ) -> LifetimeRefSet<'a> {
189        match *self {
190            Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
191            Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
192        }
193    }
194}
195
196/// Equivalent to `syn::Fields`, but replaces the AST element with a generic.
197#[derive(Debug, Clone)]
198pub struct Fields<T> {
199    pub style: Style,
200    pub fields: Vec<T>,
201    span: Option<Span>,
202    __nonexhaustive: (),
203}
204
205impl<T> Fields<T> {
206    /// Creates a new [`Fields`] struct.
207    pub fn new(style: Style, fields: Vec<T>) -> Self {
208        Self {
209            style,
210            fields,
211            span: None,
212            __nonexhaustive: (),
213        }
214    }
215
216    /// Adds a [`Span`] to [`Fields`].
217    pub fn with_span(mut self, span: Span) -> Self {
218        if self.span.is_none() {
219            self.span = Some(span);
220        }
221        self
222    }
223
224    pub fn empty_from(vd: &syn::Fields) -> Self {
225        Self::new(vd.into(), Vec::new())
226    }
227
228    /// Splits the `Fields` into its style and fields for further processing.
229    /// Returns an empty `Vec` for `Unit` data.
230    pub fn split(self) -> (Style, Vec<T>) {
231        (self.style, self.fields)
232    }
233
234    pub fn is_unit(&self) -> bool {
235        self.style.is_unit()
236    }
237
238    pub fn is_tuple(&self) -> bool {
239        self.style.is_tuple()
240    }
241
242    pub fn is_struct(&self) -> bool {
243        self.style.is_struct()
244    }
245
246    pub fn as_ref(&self) -> Fields<&T> {
247        Fields {
248            style: self.style,
249            fields: self.fields.iter().collect(),
250            span: self.span,
251            __nonexhaustive: (),
252        }
253    }
254
255    pub fn map<F, U>(self, map: F) -> Fields<U>
256    where
257        F: FnMut(T) -> U,
258    {
259        Fields {
260            style: self.style,
261            fields: self.fields.into_iter().map(map).collect(),
262            span: self.span,
263            __nonexhaustive: (),
264        }
265    }
266
267    pub fn iter(&self) -> slice::Iter<'_, T> {
268        self.fields.iter()
269    }
270
271    /// Returns the number of fields in the structure.
272    pub fn len(&self) -> usize {
273        self.fields.len()
274    }
275
276    /// Returns `true` if the `Fields` contains no fields.
277    pub fn is_empty(&self) -> bool {
278        self.fields.is_empty()
279    }
280}
281
282impl<F: FromField> Fields<F> {
283    pub fn try_from(fields: &syn::Fields) -> Result<Self> {
284        let mut errors = Error::accumulator();
285        let items = {
286            match &fields {
287                syn::Fields::Named(fields) => fields
288                    .named
289                    .iter()
290                    .filter_map(|field| {
291                        errors.handle(FromField::from_field(field).map_err(|err| {
292                            // There should always be an ident here, since this is a collection
293                            // of named fields, but `syn` doesn't prevent someone from manually
294                            // constructing an invalid collection so a guard is still warranted.
295                            if let Some(ident) = &field.ident {
296                                err.at(ident)
297                            } else {
298                                err
299                            }
300                        }))
301                    })
302                    .collect(),
303                syn::Fields::Unnamed(fields) => fields
304                    .unnamed
305                    .iter()
306                    .filter_map(|field| errors.handle(FromField::from_field(field)))
307                    .collect(),
308                syn::Fields::Unit => vec![],
309            }
310        };
311
312        errors.finish()?;
313
314        Ok(Self::new(fields.into(), items).with_span(fields.span()))
315    }
316}
317
318impl<T: ToTokens> ToTokens for Fields<T> {
319    fn to_tokens(&self, tokens: &mut TokenStream) {
320        let fields = &self.fields;
321        // An unknown Span should be `Span::call_site()`;
322        // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span
323        let span = self.span.unwrap_or_else(Span::call_site);
324
325        match self.style {
326            Style::Struct => {
327                let trailing_comma = {
328                    if fields.is_empty() {
329                        quote!()
330                    } else {
331                        quote!(,)
332                    }
333                };
334
335                tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
336            }
337            Style::Tuple => {
338                tokens.extend(quote_spanned![span => ( #(#fields),* )]);
339            }
340            Style::Unit => {}
341        }
342    }
343}
344
345impl<T: PartialEq> PartialEq for Fields<T> {
346    fn eq(&self, other: &Self) -> bool {
347        self.style == other.style && self.fields == other.fields
348    }
349}
350
351impl<T: Eq> Eq for Fields<T> {}
352
353impl<T> IntoIterator for Fields<T> {
354    type Item = T;
355    type IntoIter = vec::IntoIter<T>;
356
357    fn into_iter(self) -> Self::IntoIter {
358        self.fields.into_iter()
359    }
360}
361
362impl<T> From<Style> for Fields<T> {
363    fn from(style: Style) -> Self {
364        Self::new(style, Vec::new())
365    }
366}
367
368impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
369    fn from((style, fields): (Style, U)) -> Self {
370        style.with_fields(fields)
371    }
372}
373
374impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
375    fn uses_type_params<'a>(
376        &self,
377        options: &usage::Options,
378        type_set: &'a IdentSet,
379    ) -> IdentRefSet<'a> {
380        self.fields.uses_type_params(options, type_set)
381    }
382}
383
384impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
385    fn uses_lifetimes<'a>(
386        &self,
387        options: &usage::Options,
388        lifetimes: &'a LifetimeSet,
389    ) -> LifetimeRefSet<'a> {
390        self.fields.uses_lifetimes(options, lifetimes)
391    }
392}
393
394#[derive(Debug, Clone, Copy, PartialEq, Eq)]
395pub enum Style {
396    Tuple,
397    Struct,
398    Unit,
399}
400
401impl Style {
402    pub fn is_unit(self) -> bool {
403        self == Style::Unit
404    }
405
406    pub fn is_tuple(self) -> bool {
407        self == Style::Tuple
408    }
409
410    pub fn is_struct(self) -> bool {
411        self == Style::Struct
412    }
413
414    /// Creates a new `Fields` of the specified style with the passed-in fields.
415    fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
416        Fields::new(self, fields.into())
417    }
418}
419
420impl From<syn::Fields> for Style {
421    fn from(vd: syn::Fields) -> Self {
422        (&vd).into()
423    }
424}
425
426impl From<&syn::Fields> for Style {
427    fn from(vd: &syn::Fields) -> Self {
428        match *vd {
429            syn::Fields::Named(_) => Style::Struct,
430            syn::Fields::Unnamed(_) => Style::Tuple,
431            syn::Fields::Unit => Style::Unit,
432        }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use super::*;
439
440    // it is not possible to directly convert a TokenStream into syn::Fields, so you have
441    // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to
442    // Fields::try_from.
443    fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
444        Fields::try_from(&{
445            if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
446                s.fields
447            } else {
448                panic!();
449            }
450        })
451        .unwrap()
452    }
453
454    #[test]
455    fn test_style_eq() {
456        // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields`
457        // implement `Eq`, this test would fail, if someone accidentally removed the Eq
458        // implementation from `Style`.
459        struct _AssertEq
460        where
461            Style: Eq;
462    }
463
464    #[test]
465    fn test_fields_to_tokens_struct() {
466        let reference = quote!(
467            {
468                executable: String,
469                args: Vec<String>,
470                env: Vec<String>,
471                index: usize,
472                optional: Option<String>,
473                current_dir: String,
474            }
475        );
476        let input = quote!(
477            struct ExampleTest #reference
478        );
479
480        let fields = token_stream_to_fields(input);
481
482        let mut result = quote!();
483        fields.to_tokens(&mut result);
484        assert_eq!(result.to_string(), reference.to_string());
485    }
486
487    #[test]
488    fn test_fields_to_tokens_tuple() {
489        let reference = quote!((u64, usize, &'a T));
490        let input = quote!(
491            struct ExampleTest #reference;
492        );
493
494        let fields = token_stream_to_fields(input);
495
496        let mut result = quote!();
497        fields.to_tokens(&mut result);
498        assert_eq!(result.to_string(), reference.to_string());
499    }
500}