Skip to main content

syn/
data.rs

1use crate::attr::Attribute;
2#[cfg(feature = "parsing")]
3use crate::error::Result;
4use crate::expr::{Expr, Index, Member};
5use crate::ident::Ident;
6use crate::punctuated::{self, Punctuated};
7use crate::restriction::Visibility;
8use crate::token;
9use crate::ty::Type;
10use alloc::vec::Vec;
11
12#[doc = r" An enum variant."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct Variant {
    pub attrs: Vec<Attribute>,
    #[doc = r" Name of the variant."]
    pub ident: Ident,
    #[doc = r" Content stored in the variant."]
    pub fields: Fields,
    #[doc = r" Explicit discriminant: `Variant = 1`"]
    pub discriminant: Option<(crate::token::Eq, Expr)>,
}ast_struct! {
13    /// An enum variant.
14    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
15    pub struct Variant {
16        pub attrs: Vec<Attribute>,
17
18        /// Name of the variant.
19        pub ident: Ident,
20
21        /// Content stored in the variant.
22        pub fields: Fields,
23
24        /// Explicit discriminant: `Variant = 1`
25        pub discriminant: Option<(Token![=], Expr)>,
26    }
27}
28
29#[doc = r" Data stored within an enum variant or struct."]
#[doc = r""]
#[doc = r" # Syntax tree enum"]
#[doc = r""]
#[doc = r" This type is a [syntax tree enum]."]
#[doc = r""]
#[doc = r" [syntax tree enum]: crate::expr::Expr#syntax-tree-enums"]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub enum Fields {

    #[doc =
    r" Named fields of a struct or struct variant such as `Point { x: f64,"]
    #[doc = r" y: f64 }`."]
    Named(FieldsNamed),

    #[doc =
    r" Unnamed fields of a tuple struct or tuple variant such as `Some(T)`."]
    Unnamed(FieldsUnnamed),

    #[doc = r" Unit struct or unit variant such as `None`."]
    Unit,
}
#[doc(cfg(feature = "printing"))]
impl ::quote::ToTokens for Fields {
    fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
        match self {
            Fields::Named(_e) => _e.to_tokens(tokens),
            Fields::Unnamed(_e) => _e.to_tokens(tokens),
            Fields::Unit => {}
        }
    }
}ast_enum_of_structs! {
30    /// Data stored within an enum variant or struct.
31    ///
32    /// # Syntax tree enum
33    ///
34    /// This type is a [syntax tree enum].
35    ///
36    /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums
37    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
38    pub enum Fields {
39        /// Named fields of a struct or struct variant such as `Point { x: f64,
40        /// y: f64 }`.
41        Named(FieldsNamed),
42
43        /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
44        Unnamed(FieldsUnnamed),
45
46        /// Unit struct or unit variant such as `None`.
47        Unit,
48    }
49}
50
51#[doc =
r" Named fields of a struct or struct variant such as `Point { x: f64,"]
#[doc = r" y: f64 }`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct FieldsNamed {
    pub brace_token: token::Brace,
    pub named: Punctuated<Field, crate::token::Comma>,
}ast_struct! {
52    /// Named fields of a struct or struct variant such as `Point { x: f64,
53    /// y: f64 }`.
54    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
55    pub struct FieldsNamed {
56        pub brace_token: token::Brace,
57        pub named: Punctuated<Field, Token![,]>,
58    }
59}
60
61#[doc =
r" Unnamed fields of a tuple struct or tuple variant such as `Some(T)`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct FieldsUnnamed {
    pub paren_token: token::Paren,
    pub unnamed: Punctuated<Field, crate::token::Comma>,
}ast_struct! {
62    /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
63    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
64    pub struct FieldsUnnamed {
65        pub paren_token: token::Paren,
66        pub unnamed: Punctuated<Field, Token![,]>,
67    }
68}
69
70impl Fields {
71    /// Get an iterator over the borrowed [`Field`] items in this object. This
72    /// iterator can be used to iterate over a named or unnamed struct or
73    /// variant's fields uniformly.
74    pub fn iter(&self) -> punctuated::Iter<Field> {
75        match self {
76            Fields::Unit => crate::punctuated::empty_punctuated_iter(),
77            Fields::Named(f) => f.named.iter(),
78            Fields::Unnamed(f) => f.unnamed.iter(),
79        }
80    }
81
82    /// Get an iterator over the mutably borrowed [`Field`] items in this
83    /// object. This iterator can be used to iterate over a named or unnamed
84    /// struct or variant's fields uniformly.
85    pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
86        match self {
87            Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(),
88            Fields::Named(f) => f.named.iter_mut(),
89            Fields::Unnamed(f) => f.unnamed.iter_mut(),
90        }
91    }
92
93    /// Returns the number of fields.
94    pub fn len(&self) -> usize {
95        match self {
96            Fields::Unit => 0,
97            Fields::Named(f) => f.named.len(),
98            Fields::Unnamed(f) => f.unnamed.len(),
99        }
100    }
101
102    /// Returns `true` if there are zero fields.
103    pub fn is_empty(&self) -> bool {
104        match self {
105            Fields::Unit => true,
106            Fields::Named(f) => f.named.is_empty(),
107            Fields::Unnamed(f) => f.unnamed.is_empty(),
108        }
109    }
110
111    #[doc =
r" Get an iterator over the fields of a struct or variant as [`Member`]s."]
#[doc =
r" This iterator can be used to iterate over a named or unnamed struct or"]
#[doc = r" variant's fields uniformly."]
#[doc = r""]
#[doc = r" # Example"]
#[doc = r""]
#[doc =
r" The following is a simplistic [`Clone`] derive for structs. (A more"]
#[doc =
r" complete implementation would additionally want to infer trait bounds on"]
#[doc = r" the generic type parameters.)"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" # use quote::quote;"]
#[doc = r" #"]
#[doc =
r" fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {"]
#[doc = r"     let ident = &input.ident;"]
#[doc = r"     let members = input.fields.members();"]
#[doc =
r"     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();"]
#[doc = r"     quote! {"]
#[doc =
r"         impl #impl_generics Clone for #ident #ty_generics #where_clause {"]
#[doc = r"             fn clone(&self) -> Self {"]
#[doc = r"                 Self {"]
#[doc = r"                     #(#members: self.#members.clone()),*"]
#[doc = r"                 }"]
#[doc = r"             }"]
#[doc = r"         }"]
#[doc = r"     }"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc =
r" For structs with named fields, it produces an expression like `Self { a:"]
#[doc = r" self.a.clone() }`. For structs with unnamed fields, `Self { 0:"]
#[doc = r" self.0.clone() }`. And for unit structs, `Self {}`."]
pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ {
    Members { fields: self.iter(), index: 0 }
}return_impl_trait! {
112        /// Get an iterator over the fields of a struct or variant as [`Member`]s.
113        /// This iterator can be used to iterate over a named or unnamed struct or
114        /// variant's fields uniformly.
115        ///
116        /// # Example
117        ///
118        /// The following is a simplistic [`Clone`] derive for structs. (A more
119        /// complete implementation would additionally want to infer trait bounds on
120        /// the generic type parameters.)
121        ///
122        /// ```
123        /// # use quote::quote;
124        /// #
125        /// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
126        ///     let ident = &input.ident;
127        ///     let members = input.fields.members();
128        ///     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
129        ///     quote! {
130        ///         impl #impl_generics Clone for #ident #ty_generics #where_clause {
131        ///             fn clone(&self) -> Self {
132        ///                 Self {
133        ///                     #(#members: self.#members.clone()),*
134        ///                 }
135        ///             }
136        ///         }
137        ///     }
138        /// }
139        /// ```
140        ///
141        /// For structs with named fields, it produces an expression like `Self { a:
142        /// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
143        /// self.0.clone() }`. And for unit structs, `Self {}`.
144        pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] {
145            Members {
146                fields: self.iter(),
147                index: 0,
148            }
149        }
150    }
151}
152
153impl IntoIterator for Fields {
154    type Item = Field;
155    type IntoIter = punctuated::IntoIter<Field>;
156
157    fn into_iter(self) -> Self::IntoIter {
158        match self {
159            Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
160            Fields::Named(f) => f.named.into_iter(),
161            Fields::Unnamed(f) => f.unnamed.into_iter(),
162        }
163    }
164}
165
166impl<'a> IntoIterator for &'a Fields {
167    type Item = &'a Field;
168    type IntoIter = punctuated::Iter<'a, Field>;
169
170    fn into_iter(self) -> Self::IntoIter {
171        self.iter()
172    }
173}
174
175impl<'a> IntoIterator for &'a mut Fields {
176    type Item = &'a mut Field;
177    type IntoIter = punctuated::IterMut<'a, Field>;
178
179    fn into_iter(self) -> Self::IntoIter {
180        self.iter_mut()
181    }
182}
183
184#[doc = r" A field of a struct or enum variant."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct Field {
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    #[doc =
    r" (Non-exhaustive) Additional optional information about a field."]
    pub modifiers: FieldModifiers,
    #[doc = r" Name of the field, if any."]
    #[doc = r""]
    #[doc = r" Fields of tuple structs have no names."]
    pub ident: Option<Ident>,
    pub colon_token: Option<crate::token::Colon>,
    pub ty: Type,
    pub default: Option<(crate::token::Eq, Expr)>,
}ast_struct! {
185    /// A field of a struct or enum variant.
186    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
187    pub struct Field {
188        pub attrs: Vec<Attribute>,
189
190        pub vis: Visibility,
191
192        /// (Non-exhaustive) Additional optional information about a field.
193        pub modifiers: FieldModifiers,
194
195        /// Name of the field, if any.
196        ///
197        /// Fields of tuple structs have no names.
198        pub ident: Option<Ident>,
199
200        pub colon_token: Option<Token![:]>,
201
202        pub ty: Type,
203
204        pub default: Option<(Token![=], Expr)>,
205    }
206}
207
208#[doc = r" Additional optional information about a field."]
#[doc = r""]
#[doc = r" This data structure may grow to accommodate future Rust language"]
#[doc = r" changes, including the following in-progress RFCs:"]
#[doc = r""]
#[doc = r#" - [RFC 3323] "Restrictions", such as `mut(crate)`"#]
#[doc = r#" - [RFC 3458] "Unsafe fields""#]
#[doc = r""]
#[doc =
r" [RFC 3323]: https://rust-lang.github.io/rfcs/3323-restrictions.html"]
#[doc = r" [RFC 3458]: https://github.com/rust-lang/rfcs/pull/3458"]
#[doc(cfg(any(feature = "full", feature = "derive")))]
#[non_exhaustive]
pub struct FieldModifiers {}ast_struct! {
209    /// Additional optional information about a field.
210    ///
211    /// This data structure may grow to accommodate future Rust language
212    /// changes, including the following in-progress RFCs:
213    ///
214    /// - [RFC 3323] "Restrictions", such as `mut(crate)`
215    /// - [RFC 3458] "Unsafe fields"
216    ///
217    /// [RFC 3323]: https://rust-lang.github.io/rfcs/3323-restrictions.html
218    /// [RFC 3458]: https://github.com/rust-lang/rfcs/pull/3458
219    #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
220    #[non_exhaustive]
221    pub struct FieldModifiers {}
222}
223
224impl Default for FieldModifiers {
225    fn default() -> Self {
226        FieldModifiers {}
227    }
228}
229
230impl FieldModifiers {
231    #[cfg(feature = "parsing")]
232    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
233    pub fn require_empty(&self) -> Result<()> {
234        Ok(())
235    }
236}
237
238pub struct Members<'a> {
239    fields: punctuated::Iter<'a, Field>,
240    index: u32,
241}
242
243impl<'a> Iterator for Members<'a> {
244    type Item = Member;
245
246    fn next(&mut self) -> Option<Self::Item> {
247        let field = self.fields.next()?;
248        let member = match &field.ident {
249            Some(ident) => Member::Named(ident.clone()),
250            None => {
251                #[cfg(all(feature = "parsing", feature = "printing"))]
252                let span = crate::spanned::Spanned::span(&field.ty);
253                #[cfg(not(all(feature = "parsing", feature = "printing")))]
254                let span = proc_macro2::Span::call_site();
255                Member::Unnamed(Index {
256                    index: self.index,
257                    span,
258                })
259            }
260        };
261        self.index += 1;
262        Some(member)
263    }
264}
265
266impl<'a> Clone for Members<'a> {
267    fn clone(&self) -> Self {
268        Members {
269            fields: self.fields.clone(),
270            index: self.index,
271        }
272    }
273}
274
275#[cfg(feature = "parsing")]
276pub(crate) mod parsing {
277    use crate::attr::Attribute;
278    use crate::data::{Field, FieldModifiers, Fields, FieldsNamed, FieldsUnnamed, Variant};
279    use crate::error::Result;
280    use crate::expr::Expr;
281    use crate::ext::IdentExt as _;
282    use crate::ident::Ident;
283    #[cfg(not(feature = "full"))]
284    use crate::parse::discouraged::Speculative as _;
285    use crate::parse::{Parse, ParseStream};
286    use crate::restriction::Visibility;
287    #[cfg(not(feature = "full"))]
288    use crate::scan_expr::scan_expr;
289    use crate::token;
290    use crate::ty::Type;
291    use crate::verbatim;
292
293    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
294    impl Parse for Variant {
295        fn parse(input: ParseStream) -> Result<Self> {
296            let attrs = input.call(Attribute::parse_outer)?;
297            let _visibility: Visibility = input.parse()?;
298            let ident: Ident = input.parse()?;
299            let fields = if input.peek(token::Brace) {
300                Fields::Named(input.parse()?)
301            } else if input.peek(token::Paren) {
302                Fields::Unnamed(input.parse()?)
303            } else {
304                Fields::Unit
305            };
306            let discriminant = if input.peek(crate::token::EqToken![=]) {
307                let eq_token: crate::token::EqToken![=] = input.parse()?;
308                #[cfg(feature = "full")]
309                let discriminant: Expr = input.parse()?;
310                #[cfg(not(feature = "full"))]
311                let discriminant = {
312                    let begin = input.cursor();
313                    let ahead = input.fork();
314                    let mut discriminant: Result<Expr> = ahead.parse();
315                    if discriminant.is_ok() {
316                        input.advance_to(&ahead);
317                    } else if scan_expr(input).is_ok() {
318                        discriminant = Ok(Expr::Verbatim(verbatim::between(begin, input.cursor())));
319                    }
320                    discriminant?
321                };
322                Some((eq_token, discriminant))
323            } else {
324                None
325            };
326            Ok(Variant {
327                attrs,
328                ident,
329                fields,
330                discriminant,
331            })
332        }
333    }
334
335    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
336    impl Parse for FieldsNamed {
337        fn parse(input: ParseStream) -> Result<Self> {
338            let content;
339            Ok(FieldsNamed {
340                brace_token: match crate::__private::parse_braces(&input) {
    crate::__private::Ok(braces) => {
        content = braces.content;
        _ = content;
        braces.token
    }
    crate::__private::Err(error) => { return crate::__private::Err(error); }
}braced!(content in input),
341                named: content.parse_terminated(Field::parse_named, crate::token::CommaToken![,])?,
342            })
343        }
344    }
345
346    #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
347    impl Parse for FieldsUnnamed {
348        fn parse(input: ParseStream) -> Result<Self> {
349            let content;
350            Ok(FieldsUnnamed {
351                paren_token: match crate::__private::parse_parens(&input) {
    crate::__private::Ok(parens) => {
        content = parens.content;
        _ = content;
        parens.token
    }
    crate::__private::Err(error) => { return crate::__private::Err(error); }
}parenthesized!(content in input),
352                unnamed: content.parse_terminated(Field::parse_unnamed, crate::token::CommaToken![,])?,
353            })
354        }
355    }
356
357    impl Field {
358        /// Parses a named (braced struct) field.
359        #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
360        pub fn parse_named(input: ParseStream) -> Result<Self> {
361            let attrs = input.call(Attribute::parse_outer)?;
362            let vis: Visibility = input.parse()?;
363
364            let unnamed_field = truecfg!(feature = "full") && input.peek(crate::token::UnderscoreToken![_]);
365            let ident = if unnamed_field {
366                input.call(Ident::parse_any)
367            } else {
368                input.parse()
369            }?;
370
371            let colon_token: crate::token::ColonToken![:] = input.parse()?;
372
373            let ty: Type = if unnamed_field
374                && (input.peek(crate::token::StructToken![struct])
375                    || input.peek(crate::token::UnionToken![union]) && input.peek2(token::Brace))
376            {
377                let begin = input.cursor();
378                input.call(Ident::parse_any)?;
379                input.parse::<FieldsNamed>()?;
380                Type::Verbatim(verbatim::between(begin, input.cursor()))
381            } else {
382                input.parse()?
383            };
384
385            let default = if input.peek(crate::token::EqToken![=]) {
386                let eq_token: crate::token::EqToken![=] = input.parse()?;
387                let expr: Expr = input.parse()?;
388                Some((eq_token, expr))
389            } else {
390                None
391            };
392
393            Ok(Field {
394                attrs,
395                vis,
396                modifiers: FieldModifiers {},
397                ident: Some(ident),
398                colon_token: Some(colon_token),
399                ty,
400                default,
401            })
402        }
403
404        /// Parses an unnamed (tuple struct) field.
405        #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
406        pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
407            let attrs = input.call(Attribute::parse_outer)?;
408            let vis: Visibility = input.parse()?;
409            let ty: Type = input.parse()?;
410
411            if input.peek(crate::token::EqToken![=]) {
412                input.parse::<crate::token::EqToken![=]>()?;
413                let start_span = input.span();
414                input.parse::<Expr>()?;
415                let end_span = input.cursor().prev_span();
416                return Err(crate::error::new2(
417                    start_span,
418                    end_span,
419                    "field default value is only supported in structs with named fields",
420                ));
421            }
422
423            Ok(Field {
424                attrs,
425                vis,
426                modifiers: FieldModifiers {},
427                ident: None,
428                colon_token: None,
429                ty,
430                default: None,
431            })
432        }
433    }
434}
435
436#[cfg(feature = "printing")]
437mod printing {
438    use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant};
439    use crate::print::TokensOrDefault;
440    use proc_macro2::TokenStream;
441    use quote::{ToTokens, TokenStreamExt as _};
442
443    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
444    impl ToTokens for Variant {
445        fn to_tokens(&self, tokens: &mut TokenStream) {
446            tokens.append_all(&self.attrs);
447            self.ident.to_tokens(tokens);
448            self.fields.to_tokens(tokens);
449            if let Some((eq_token, disc)) = &self.discriminant {
450                eq_token.to_tokens(tokens);
451                disc.to_tokens(tokens);
452            }
453        }
454    }
455
456    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
457    impl ToTokens for FieldsNamed {
458        fn to_tokens(&self, tokens: &mut TokenStream) {
459            self.brace_token.surround(tokens, |tokens| {
460                self.named.to_tokens(tokens);
461            });
462        }
463    }
464
465    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
466    impl ToTokens for FieldsUnnamed {
467        fn to_tokens(&self, tokens: &mut TokenStream) {
468            self.paren_token.surround(tokens, |tokens| {
469                self.unnamed.to_tokens(tokens);
470            });
471        }
472    }
473
474    #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
475    impl ToTokens for Field {
476        fn to_tokens(&self, tokens: &mut TokenStream) {
477            tokens.append_all(&self.attrs);
478            self.vis.to_tokens(tokens);
479            if let Some(ident) = &self.ident {
480                ident.to_tokens(tokens);
481                TokensOrDefault(&self.colon_token).to_tokens(tokens);
482            }
483            self.ty.to_tokens(tokens);
484            if let Some((eq_token, default)) = &self.default {
485                eq_token.to_tokens(tokens);
486                default.to_tokens(tokens);
487            }
488        }
489    }
490}