Skip to main content

syn/
data.rs

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