syn/
data.rs

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