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