syn/
data.rs

1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5    /// An enum variant.
6    ///
7    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
8    /// feature.*
9    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
10    pub struct Variant {
11        /// Attributes tagged on the variant.
12        pub attrs: Vec<Attribute>,
13
14        /// Name of the variant.
15        pub ident: Ident,
16
17        /// Content stored in the variant.
18        pub fields: Fields,
19
20        /// Explicit discriminant: `Variant = 1`
21        pub discriminant: Option<(Token![=], Expr)>,
22    }
23}
24
25ast_enum_of_structs! {
26    /// Data stored within an enum variant or struct.
27    ///
28    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
29    /// feature.*
30    ///
31    /// # Syntax tree enum
32    ///
33    /// This type is a [syntax tree enum].
34    ///
35    /// [syntax tree enum]: Expr#syntax-tree-enums
36    #[cfg_attr(doc_cfg, 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    ///
54    /// *This type is available only if Syn is built with the `"derive"` or
55    /// `"full"` feature.*
56    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
57    pub struct FieldsNamed {
58        pub brace_token: token::Brace,
59        pub named: Punctuated<Field, Token![,]>,
60    }
61}
62
63ast_struct! {
64    /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
65    ///
66    /// *This type is available only if Syn is built with the `"derive"` or
67    /// `"full"` feature.*
68    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
69    pub struct FieldsUnnamed {
70        pub paren_token: token::Paren,
71        pub unnamed: Punctuated<Field, Token![,]>,
72    }
73}
74
75impl Fields {
76    /// Get an iterator over the borrowed [`Field`] items in this object. This
77    /// iterator can be used to iterate over a named or unnamed struct or
78    /// variant's fields uniformly.
79    pub fn iter(&self) -> punctuated::Iter<Field> {
80        match self {
81            Fields::Unit => crate::punctuated::empty_punctuated_iter(),
82            Fields::Named(f) => f.named.iter(),
83            Fields::Unnamed(f) => f.unnamed.iter(),
84        }
85    }
86
87    /// Get an iterator over the mutably borrowed [`Field`] items in this
88    /// object. This iterator can be used to iterate over a named or unnamed
89    /// struct or variant's fields uniformly.
90    pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
91        match self {
92            Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(),
93            Fields::Named(f) => f.named.iter_mut(),
94            Fields::Unnamed(f) => f.unnamed.iter_mut(),
95        }
96    }
97
98    /// Returns the number of fields.
99    pub fn len(&self) -> usize {
100        match self {
101            Fields::Unit => 0,
102            Fields::Named(f) => f.named.len(),
103            Fields::Unnamed(f) => f.unnamed.len(),
104        }
105    }
106
107    /// Returns `true` if there are zero fields.
108    pub fn is_empty(&self) -> bool {
109        match self {
110            Fields::Unit => true,
111            Fields::Named(f) => f.named.is_empty(),
112            Fields::Unnamed(f) => f.unnamed.is_empty(),
113        }
114    }
115}
116
117impl IntoIterator for Fields {
118    type Item = Field;
119    type IntoIter = punctuated::IntoIter<Field>;
120
121    fn into_iter(self) -> Self::IntoIter {
122        match self {
123            Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
124            Fields::Named(f) => f.named.into_iter(),
125            Fields::Unnamed(f) => f.unnamed.into_iter(),
126        }
127    }
128}
129
130impl<'a> IntoIterator for &'a Fields {
131    type Item = &'a Field;
132    type IntoIter = punctuated::Iter<'a, Field>;
133
134    fn into_iter(self) -> Self::IntoIter {
135        self.iter()
136    }
137}
138
139impl<'a> IntoIterator for &'a mut Fields {
140    type Item = &'a mut Field;
141    type IntoIter = punctuated::IterMut<'a, Field>;
142
143    fn into_iter(self) -> Self::IntoIter {
144        self.iter_mut()
145    }
146}
147
148ast_struct! {
149    /// A field of a struct or enum variant.
150    ///
151    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
152    /// feature.*
153    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
154    pub struct Field {
155        /// Attributes tagged on the field.
156        pub attrs: Vec<Attribute>,
157
158        /// Visibility of the field.
159        pub vis: Visibility,
160
161        /// Name of the field, if any.
162        ///
163        /// Fields of tuple structs have no names.
164        pub ident: Option<Ident>,
165
166        pub colon_token: Option<Token![:]>,
167
168        /// Type of the field.
169        pub ty: Type,
170    }
171}
172
173ast_enum_of_structs! {
174    /// The visibility level of an item: inherited or `pub` or
175    /// `pub(restricted)`.
176    ///
177    /// *This type is available only if Syn is built with the `"derive"` or `"full"`
178    /// feature.*
179    ///
180    /// # Syntax tree enum
181    ///
182    /// This type is a [syntax tree enum].
183    ///
184    /// [syntax tree enum]: Expr#syntax-tree-enums
185    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
186    pub enum Visibility {
187        /// A public visibility level: `pub`.
188        Public(VisPublic),
189
190        /// A crate-level visibility: `crate`.
191        Crate(VisCrate),
192
193        /// A visibility level restricted to some path: `pub(self)` or
194        /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
195        Restricted(VisRestricted),
196
197        /// An inherited visibility, which usually means private.
198        Inherited,
199    }
200}
201
202ast_struct! {
203    /// A public visibility level: `pub`.
204    ///
205    /// *This type is available only if Syn is built with the `"derive"` or
206    /// `"full"` feature.*
207    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
208    pub struct VisPublic {
209        pub pub_token: Token![pub],
210    }
211}
212
213ast_struct! {
214    /// A crate-level visibility: `crate`.
215    ///
216    /// *This type is available only if Syn is built with the `"derive"` or
217    /// `"full"` feature.*
218    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
219    pub struct VisCrate {
220        pub crate_token: Token![crate],
221    }
222}
223
224ast_struct! {
225    /// A visibility level restricted to some path: `pub(self)` or
226    /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
227    ///
228    /// *This type is available only if Syn is built with the `"derive"` or
229    /// `"full"` feature.*
230    #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
231    pub struct VisRestricted {
232        pub pub_token: Token![pub],
233        pub paren_token: token::Paren,
234        pub in_token: Option<Token![in]>,
235        pub path: Box<Path>,
236    }
237}
238
239#[cfg(feature = "parsing")]
240pub mod parsing {
241    use super::*;
242    use crate::ext::IdentExt;
243    use crate::parse::discouraged::Speculative;
244    use crate::parse::{Parse, ParseStream, Result};
245
246    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
247    impl Parse for Variant {
248        fn parse(input: ParseStream) -> Result<Self> {
249            let attrs = input.call(Attribute::parse_outer)?;
250            let _visibility: Visibility = input.parse()?;
251            let ident: Ident = input.parse()?;
252            let fields = if input.peek(token::Brace) {
253                Fields::Named(input.parse()?)
254            } else if input.peek(token::Paren) {
255                Fields::Unnamed(input.parse()?)
256            } else {
257                Fields::Unit
258            };
259            let discriminant = if input.peek(Token![=]) {
260                let eq_token: Token![=] = input.parse()?;
261                let discriminant: Expr = input.parse()?;
262                Some((eq_token, discriminant))
263            } else {
264                None
265            };
266            Ok(Variant {
267                attrs,
268                ident,
269                fields,
270                discriminant,
271            })
272        }
273    }
274
275    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
276    impl Parse for FieldsNamed {
277        fn parse(input: ParseStream) -> Result<Self> {
278            let content;
279            Ok(FieldsNamed {
280                brace_token: braced!(content in input),
281                named: content.parse_terminated(Field::parse_named)?,
282            })
283        }
284    }
285
286    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
287    impl Parse for FieldsUnnamed {
288        fn parse(input: ParseStream) -> Result<Self> {
289            let content;
290            Ok(FieldsUnnamed {
291                paren_token: parenthesized!(content in input),
292                unnamed: content.parse_terminated(Field::parse_unnamed)?,
293            })
294        }
295    }
296
297    impl Field {
298        /// Parses a named (braced struct) field.
299        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
300        pub fn parse_named(input: ParseStream) -> Result<Self> {
301            Ok(Field {
302                attrs: input.call(Attribute::parse_outer)?,
303                vis: input.parse()?,
304                ident: Some(if input.peek(Token![_]) {
305                    input.call(Ident::parse_any)
306                } else {
307                    input.parse()
308                }?),
309                colon_token: Some(input.parse()?),
310                ty: input.parse()?,
311            })
312        }
313
314        /// Parses an unnamed (tuple struct) field.
315        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
316        pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
317            Ok(Field {
318                attrs: input.call(Attribute::parse_outer)?,
319                vis: input.parse()?,
320                ident: None,
321                colon_token: None,
322                ty: input.parse()?,
323            })
324        }
325    }
326
327    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
328    impl Parse for Visibility {
329        fn parse(input: ParseStream) -> Result<Self> {
330            // Recognize an empty None-delimited group, as produced by a $:vis
331            // matcher that matched no tokens.
332            if input.peek(token::Group) {
333                let ahead = input.fork();
334                let group = crate::group::parse_group(&ahead)?;
335                if group.content.is_empty() {
336                    input.advance_to(&ahead);
337                    return Ok(Visibility::Inherited);
338                }
339            }
340
341            if input.peek(Token![pub]) {
342                Self::parse_pub(input)
343            } else if input.peek(Token![crate]) {
344                Self::parse_crate(input)
345            } else {
346                Ok(Visibility::Inherited)
347            }
348        }
349    }
350
351    impl Visibility {
352        fn parse_pub(input: ParseStream) -> Result<Self> {
353            let pub_token = input.parse::<Token![pub]>()?;
354
355            if input.peek(token::Paren) {
356                let ahead = input.fork();
357
358                let content;
359                let paren_token = parenthesized!(content in ahead);
360                if content.peek(Token![crate])
361                    || content.peek(Token![self])
362                    || content.peek(Token![super])
363                {
364                    let path = content.call(Ident::parse_any)?;
365
366                    // Ensure there are no additional tokens within `content`.
367                    // Without explicitly checking, we may misinterpret a tuple
368                    // field as a restricted visibility, causing a parse error.
369                    // e.g. `pub (crate::A, crate::B)` (Issue #720).
370                    if content.is_empty() {
371                        input.advance_to(&ahead);
372                        return Ok(Visibility::Restricted(VisRestricted {
373                            pub_token,
374                            paren_token,
375                            in_token: None,
376                            path: Box::new(Path::from(path)),
377                        }));
378                    }
379                } else if content.peek(Token![in]) {
380                    let in_token: Token![in] = content.parse()?;
381                    let path = content.call(Path::parse_mod_style)?;
382
383                    input.advance_to(&ahead);
384                    return Ok(Visibility::Restricted(VisRestricted {
385                        pub_token,
386                        paren_token,
387                        in_token: Some(in_token),
388                        path: Box::new(path),
389                    }));
390                }
391            }
392
393            Ok(Visibility::Public(VisPublic { pub_token }))
394        }
395
396        fn parse_crate(input: ParseStream) -> Result<Self> {
397            if input.peek2(Token![::]) {
398                Ok(Visibility::Inherited)
399            } else {
400                Ok(Visibility::Crate(VisCrate {
401                    crate_token: input.parse()?,
402                }))
403            }
404        }
405
406        #[cfg(feature = "full")]
407        pub(crate) fn is_some(&self) -> bool {
408            match self {
409                Visibility::Inherited => false,
410                _ => true,
411            }
412        }
413    }
414}
415
416#[cfg(feature = "printing")]
417mod printing {
418    use super::*;
419    use crate::print::TokensOrDefault;
420    use proc_macro2::TokenStream;
421    use quote::{ToTokens, TokenStreamExt};
422
423    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
424    impl ToTokens for Variant {
425        fn to_tokens(&self, tokens: &mut TokenStream) {
426            tokens.append_all(&self.attrs);
427            self.ident.to_tokens(tokens);
428            self.fields.to_tokens(tokens);
429            if let Some((eq_token, disc)) = &self.discriminant {
430                eq_token.to_tokens(tokens);
431                disc.to_tokens(tokens);
432            }
433        }
434    }
435
436    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
437    impl ToTokens for FieldsNamed {
438        fn to_tokens(&self, tokens: &mut TokenStream) {
439            self.brace_token.surround(tokens, |tokens| {
440                self.named.to_tokens(tokens);
441            });
442        }
443    }
444
445    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
446    impl ToTokens for FieldsUnnamed {
447        fn to_tokens(&self, tokens: &mut TokenStream) {
448            self.paren_token.surround(tokens, |tokens| {
449                self.unnamed.to_tokens(tokens);
450            });
451        }
452    }
453
454    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
455    impl ToTokens for Field {
456        fn to_tokens(&self, tokens: &mut TokenStream) {
457            tokens.append_all(&self.attrs);
458            self.vis.to_tokens(tokens);
459            if let Some(ident) = &self.ident {
460                ident.to_tokens(tokens);
461                TokensOrDefault(&self.colon_token).to_tokens(tokens);
462            }
463            self.ty.to_tokens(tokens);
464        }
465    }
466
467    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
468    impl ToTokens for VisPublic {
469        fn to_tokens(&self, tokens: &mut TokenStream) {
470            self.pub_token.to_tokens(tokens);
471        }
472    }
473
474    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
475    impl ToTokens for VisCrate {
476        fn to_tokens(&self, tokens: &mut TokenStream) {
477            self.crate_token.to_tokens(tokens);
478        }
479    }
480
481    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
482    impl ToTokens for VisRestricted {
483        fn to_tokens(&self, tokens: &mut TokenStream) {
484            self.pub_token.to_tokens(tokens);
485            self.paren_token.surround(tokens, |tokens| {
486                // TODO: If we have a path which is not "self" or "super" or
487                // "crate", automatically add the "in" token.
488                self.in_token.to_tokens(tokens);
489                self.path.to_tokens(tokens);
490            });
491        }
492    }
493}