syn/
data.rs

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