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::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 `true` if this instance is `Data::Enum`.
110    pub fn is_enum(&self) -> bool {
111        match *self {
112            Data::Enum(_) => true,
113            Data::Struct(_) => false,
114        }
115    }
116
117    /// Returns `true` if this instance is `Data::Struct`.
118    pub fn is_struct(&self) -> bool {
119        !self.is_enum()
120    }
121}
122
123impl<V: FromVariant, F: FromField> Data<V, F> {
124    /// Attempt to convert from a `syn::Data` instance.
125    pub fn try_from(body: &syn::Data) -> Result<Self> {
126        match *body {
127            syn::Data::Enum(ref data) => {
128                let mut errors = Error::accumulator();
129                let items = data
130                    .variants
131                    .iter()
132                    .filter_map(|v| errors.handle(FromVariant::from_variant(v)))
133                    .collect();
134
135                errors.finish_with(Data::Enum(items))
136            }
137            syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)),
138            // This deliberately doesn't set a span on the error message, as the error is most useful if
139            // applied to the call site of the offending macro. Given that the message is very generic,
140            // putting it on the union keyword ends up being confusing.
141            syn::Data::Union(_) => Err(Error::custom("Unions are not supported")),
142        }
143    }
144}
145
146impl<V: UsesTypeParams, F: UsesTypeParams> UsesTypeParams for Data<V, F> {
147    fn uses_type_params<'a>(
148        &self,
149        options: &usage::Options,
150        type_set: &'a IdentSet,
151    ) -> IdentRefSet<'a> {
152        match *self {
153            Data::Struct(ref v) => v.uses_type_params(options, type_set),
154            Data::Enum(ref v) => v.uses_type_params(options, type_set),
155        }
156    }
157}
158
159impl<V: UsesLifetimes, F: UsesLifetimes> UsesLifetimes for Data<V, F> {
160    fn uses_lifetimes<'a>(
161        &self,
162        options: &usage::Options,
163        lifetimes: &'a LifetimeSet,
164    ) -> LifetimeRefSet<'a> {
165        match *self {
166            Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
167            Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
168        }
169    }
170}
171
172/// Equivalent to `syn::Fields`, but replaces the AST element with a generic.
173#[derive(Debug, Clone)]
174pub struct Fields<T> {
175    pub style: Style,
176    pub fields: Vec<T>,
177    span: Option<Span>,
178    __nonexhaustive: (),
179}
180
181impl<T> Fields<T> {
182    /// Creates a new [`Fields`] struct.
183    pub fn new(style: Style, fields: Vec<T>) -> Self {
184        Self {
185            style,
186            fields,
187            span: None,
188            __nonexhaustive: (),
189        }
190    }
191
192    /// Adds a [`Span`] to [`Fields`].
193    pub fn with_span(mut self, span: Span) -> Self {
194        if self.span.is_none() {
195            self.span = Some(span);
196        }
197        self
198    }
199
200    pub fn empty_from(vd: &syn::Fields) -> Self {
201        Self::new(vd.into(), Vec::new())
202    }
203
204    /// Splits the `Fields` into its style and fields for further processing.
205    /// Returns an empty `Vec` for `Unit` data.
206    pub fn split(self) -> (Style, Vec<T>) {
207        (self.style, self.fields)
208    }
209
210    /// Returns true if this variant's data makes it a newtype.
211    pub fn is_newtype(&self) -> bool {
212        self.style == Style::Tuple && self.len() == 1
213    }
214
215    pub fn is_unit(&self) -> bool {
216        self.style.is_unit()
217    }
218
219    pub fn is_tuple(&self) -> bool {
220        self.style.is_tuple()
221    }
222
223    pub fn is_struct(&self) -> bool {
224        self.style.is_struct()
225    }
226
227    pub fn as_ref(&self) -> Fields<&T> {
228        Fields {
229            style: self.style,
230            fields: self.fields.iter().collect(),
231            span: self.span,
232            __nonexhaustive: (),
233        }
234    }
235
236    pub fn map<F, U>(self, map: F) -> Fields<U>
237    where
238        F: FnMut(T) -> U,
239    {
240        Fields {
241            style: self.style,
242            fields: self.fields.into_iter().map(map).collect(),
243            span: self.span,
244            __nonexhaustive: (),
245        }
246    }
247
248    pub fn iter(&self) -> slice::Iter<'_, T> {
249        self.fields.iter()
250    }
251
252    /// Returns the number of fields in the structure.
253    pub fn len(&self) -> usize {
254        self.fields.len()
255    }
256
257    /// Returns `true` if the `Fields` contains no fields.
258    pub fn is_empty(&self) -> bool {
259        self.fields.is_empty()
260    }
261}
262
263impl<F: FromField> Fields<F> {
264    pub fn try_from(fields: &syn::Fields) -> Result<Self> {
265        let mut errors = Error::accumulator();
266        let items = {
267            match &fields {
268                syn::Fields::Named(fields) => fields
269                    .named
270                    .iter()
271                    .filter_map(|field| {
272                        errors.handle(FromField::from_field(field).map_err(|err| {
273                            // There should always be an ident here, since this is a collection
274                            // of named fields, but `syn` doesn't prevent someone from manually
275                            // constructing an invalid collection so a guard is still warranted.
276                            if let Some(ident) = &field.ident {
277                                err.at(ident)
278                            } else {
279                                err
280                            }
281                        }))
282                    })
283                    .collect(),
284                syn::Fields::Unnamed(fields) => fields
285                    .unnamed
286                    .iter()
287                    .filter_map(|field| errors.handle(FromField::from_field(field)))
288                    .collect(),
289                syn::Fields::Unit => vec![],
290            }
291        };
292
293        errors.finish()?;
294
295        Ok(Self::new(fields.into(), items).with_span(fields.span()))
296    }
297}
298
299impl<T: ToTokens> ToTokens for Fields<T> {
300    fn to_tokens(&self, tokens: &mut TokenStream) {
301        let fields = &self.fields;
302        // An unknown Span should be `Span::call_site()`;
303        // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span
304        let span = self.span.unwrap_or_else(Span::call_site);
305
306        match self.style {
307            Style::Struct => {
308                let trailing_comma = {
309                    if fields.is_empty() {
310                        quote!()
311                    } else {
312                        quote!(,)
313                    }
314                };
315
316                tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]);
317            }
318            Style::Tuple => {
319                tokens.extend(quote_spanned![span => ( #(#fields),* )]);
320            }
321            Style::Unit => {}
322        }
323    }
324}
325
326impl<T: PartialEq> PartialEq for Fields<T> {
327    fn eq(&self, other: &Self) -> bool {
328        self.style == other.style && self.fields == other.fields
329    }
330}
331
332impl<T: Eq> Eq for Fields<T> {}
333
334impl<T> IntoIterator for Fields<T> {
335    type Item = T;
336    type IntoIter = vec::IntoIter<T>;
337
338    fn into_iter(self) -> Self::IntoIter {
339        self.fields.into_iter()
340    }
341}
342
343impl<T> From<Style> for Fields<T> {
344    fn from(style: Style) -> Self {
345        Self::new(style, Vec::new())
346    }
347}
348
349impl<T, U: Into<Vec<T>>> From<(Style, U)> for Fields<T> {
350    fn from((style, fields): (Style, U)) -> Self {
351        style.with_fields(fields)
352    }
353}
354
355impl<T: UsesTypeParams> UsesTypeParams for Fields<T> {
356    fn uses_type_params<'a>(
357        &self,
358        options: &usage::Options,
359        type_set: &'a IdentSet,
360    ) -> IdentRefSet<'a> {
361        self.fields.uses_type_params(options, type_set)
362    }
363}
364
365impl<T: UsesLifetimes> UsesLifetimes for Fields<T> {
366    fn uses_lifetimes<'a>(
367        &self,
368        options: &usage::Options,
369        lifetimes: &'a LifetimeSet,
370    ) -> LifetimeRefSet<'a> {
371        self.fields.uses_lifetimes(options, lifetimes)
372    }
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
376pub enum Style {
377    Tuple,
378    Struct,
379    Unit,
380}
381
382impl Style {
383    pub fn is_unit(self) -> bool {
384        self == Style::Unit
385    }
386
387    pub fn is_tuple(self) -> bool {
388        self == Style::Tuple
389    }
390
391    pub fn is_struct(self) -> bool {
392        self == Style::Struct
393    }
394
395    /// Creates a new `Fields` of the specified style with the passed-in fields.
396    fn with_fields<T, U: Into<Vec<T>>>(self, fields: U) -> Fields<T> {
397        Fields::new(self, fields.into())
398    }
399}
400
401impl From<syn::Fields> for Style {
402    fn from(vd: syn::Fields) -> Self {
403        (&vd).into()
404    }
405}
406
407impl From<&syn::Fields> for Style {
408    fn from(vd: &syn::Fields) -> Self {
409        match *vd {
410            syn::Fields::Named(_) => Style::Struct,
411            syn::Fields::Unnamed(_) => Style::Tuple,
412            syn::Fields::Unit => Style::Unit,
413        }
414    }
415}
416
417#[cfg(test)]
418mod tests {
419    use super::*;
420
421    // it is not possible to directly convert a TokenStream into syn::Fields, so you have
422    // to convert the TokenStream into DeriveInput first and then pass the syn::Fields to
423    // Fields::try_from.
424    fn token_stream_to_fields(input: TokenStream) -> Fields<syn::Field> {
425        Fields::try_from(&{
426            if let syn::Data::Struct(s) = syn::parse2::<syn::DeriveInput>(input).unwrap().data {
427                s.fields
428            } else {
429                panic!();
430            }
431        })
432        .unwrap()
433    }
434
435    #[test]
436    fn test_style_eq() {
437        // `Fields` implements `Eq` manually, so it has to be ensured, that all fields of `Fields`
438        // implement `Eq`, this test would fail, if someone accidentally removed the Eq
439        // implementation from `Style`.
440        struct _AssertEq
441        where
442            Style: Eq;
443    }
444
445    #[test]
446    fn test_fields_to_tokens_struct() {
447        let reference = quote!(
448            {
449                executable: String,
450                args: Vec<String>,
451                env: Vec<String>,
452                index: usize,
453                optional: Option<String>,
454                current_dir: String,
455            }
456        );
457        let input = quote!(
458            struct ExampleTest #reference
459        );
460
461        let fields = token_stream_to_fields(input);
462
463        let mut result = quote!();
464        fields.to_tokens(&mut result);
465        assert_eq!(result.to_string(), reference.to_string());
466    }
467
468    #[test]
469    fn test_fields_to_tokens_tuple() {
470        let reference = quote!((u64, usize, &'a T));
471        let input = quote!(
472            struct ExampleTest #reference;
473        );
474
475        let fields = token_stream_to_fields(input);
476
477        let mut result = quote!();
478        fields.to_tokens(&mut result);
479        assert_eq!(result.to_string(), reference.to_string());
480    }
481}