1 use super::*;
2 use crate::punctuated::Punctuated;
3 
4 ast_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 
25 ast_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 
50 ast_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 
63 ast_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 
75 impl 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.
iter(&self) -> punctuated::Iter<Field>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.
iter_mut(&mut self) -> punctuated::IterMut<Field>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.
len(&self) -> usize99     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.
is_empty(&self) -> bool108     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 
117 impl IntoIterator for Fields {
118     type Item = Field;
119     type IntoIter = punctuated::IntoIter<Field>;
120 
into_iter(self) -> Self::IntoIter121     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 
130 impl<'a> IntoIterator for &'a Fields {
131     type Item = &'a Field;
132     type IntoIter = punctuated::Iter<'a, Field>;
133 
into_iter(self) -> Self::IntoIter134     fn into_iter(self) -> Self::IntoIter {
135         self.iter()
136     }
137 }
138 
139 impl<'a> IntoIterator for &'a mut Fields {
140     type Item = &'a mut Field;
141     type IntoIter = punctuated::IterMut<'a, Field>;
142 
into_iter(self) -> Self::IntoIter143     fn into_iter(self) -> Self::IntoIter {
144         self.iter_mut()
145     }
146 }
147 
148 ast_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 
173 ast_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 
202 ast_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 
213 ast_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 
224 ast_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")]
240 pub 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 {
parse(input: ParseStream) -> Result<Self>248         fn parse(input: ParseStream) -> Result<Self> {
249             let mut 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                 let fields = parse_braced(input, &mut attrs)?;
254                 Fields::Named(fields)
255             } else if input.peek(token::Paren) {
256                 Fields::Unnamed(input.parse()?)
257             } else {
258                 Fields::Unit
259             };
260             let discriminant = if input.peek(Token![=]) {
261                 let eq_token: Token![=] = input.parse()?;
262                 let discriminant: Expr = input.parse()?;
263                 Some((eq_token, discriminant))
264             } else {
265                 None
266             };
267             Ok(Variant {
268                 attrs,
269                 ident,
270                 fields,
271                 discriminant,
272             })
273         }
274     }
275 
276     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
277     impl Parse for FieldsNamed {
parse(input: ParseStream) -> Result<Self>278         fn parse(input: ParseStream) -> Result<Self> {
279             let content;
280             Ok(FieldsNamed {
281                 brace_token: braced!(content in input),
282                 named: content.parse_terminated(Field::parse_named)?,
283             })
284         }
285     }
286 
287     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
288     impl Parse for FieldsUnnamed {
parse(input: ParseStream) -> Result<Self>289         fn parse(input: ParseStream) -> Result<Self> {
290             let content;
291             Ok(FieldsUnnamed {
292                 paren_token: parenthesized!(content in input),
293                 unnamed: content.parse_terminated(Field::parse_unnamed)?,
294             })
295         }
296     }
297 
parse_braced( input: ParseStream, attrs: &mut Vec<Attribute>, ) -> Result<FieldsNamed>298     pub(crate) fn parse_braced(
299         input: ParseStream,
300         attrs: &mut Vec<Attribute>,
301     ) -> Result<FieldsNamed> {
302         let content;
303         let brace_token = braced!(content in input);
304         attr::parsing::parse_inner(&content, attrs)?;
305         let named = content.parse_terminated(Field::parse_named)?;
306         Ok(FieldsNamed { brace_token, named })
307     }
308 
309     impl Field {
310         /// Parses a named (braced struct) field.
311         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_named(input: ParseStream) -> Result<Self>312         pub fn parse_named(input: ParseStream) -> Result<Self> {
313             Ok(Field {
314                 attrs: input.call(Attribute::parse_outer)?,
315                 vis: input.parse()?,
316                 ident: Some(input.parse()?),
317                 colon_token: Some(input.parse()?),
318                 ty: input.parse()?,
319             })
320         }
321 
322         /// Parses an unnamed (tuple struct) field.
323         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_unnamed(input: ParseStream) -> Result<Self>324         pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
325             Ok(Field {
326                 attrs: input.call(Attribute::parse_outer)?,
327                 vis: input.parse()?,
328                 ident: None,
329                 colon_token: None,
330                 ty: input.parse()?,
331             })
332         }
333     }
334 
335     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
336     impl Parse for Visibility {
parse(input: ParseStream) -> Result<Self>337         fn parse(input: ParseStream) -> Result<Self> {
338             // Recognize an empty None-delimited group, as produced by a $:vis
339             // matcher that matched no tokens.
340             if input.peek(token::Group) {
341                 let ahead = input.fork();
342                 let group = crate::group::parse_group(&ahead)?;
343                 if group.content.is_empty() {
344                     input.advance_to(&ahead);
345                     return Ok(Visibility::Inherited);
346                 }
347             }
348 
349             if input.peek(Token![pub]) {
350                 Self::parse_pub(input)
351             } else if input.peek(Token![crate]) {
352                 Self::parse_crate(input)
353             } else {
354                 Ok(Visibility::Inherited)
355             }
356         }
357     }
358 
359     impl Visibility {
parse_pub(input: ParseStream) -> Result<Self>360         fn parse_pub(input: ParseStream) -> Result<Self> {
361             let pub_token = input.parse::<Token![pub]>()?;
362 
363             if input.peek(token::Paren) {
364                 let ahead = input.fork();
365 
366                 let content;
367                 let paren_token = parenthesized!(content in ahead);
368                 if content.peek(Token![crate])
369                     || content.peek(Token![self])
370                     || content.peek(Token![super])
371                 {
372                     let path = content.call(Ident::parse_any)?;
373 
374                     // Ensure there are no additional tokens within `content`.
375                     // Without explicitly checking, we may misinterpret a tuple
376                     // field as a restricted visibility, causing a parse error.
377                     // e.g. `pub (crate::A, crate::B)` (Issue #720).
378                     if content.is_empty() {
379                         input.advance_to(&ahead);
380                         return Ok(Visibility::Restricted(VisRestricted {
381                             pub_token,
382                             paren_token,
383                             in_token: None,
384                             path: Box::new(Path::from(path)),
385                         }));
386                     }
387                 } else if content.peek(Token![in]) {
388                     let in_token: Token![in] = content.parse()?;
389                     let path = content.call(Path::parse_mod_style)?;
390 
391                     input.advance_to(&ahead);
392                     return Ok(Visibility::Restricted(VisRestricted {
393                         pub_token,
394                         paren_token,
395                         in_token: Some(in_token),
396                         path: Box::new(path),
397                     }));
398                 }
399             }
400 
401             Ok(Visibility::Public(VisPublic { pub_token }))
402         }
403 
parse_crate(input: ParseStream) -> Result<Self>404         fn parse_crate(input: ParseStream) -> Result<Self> {
405             if input.peek2(Token![::]) {
406                 Ok(Visibility::Inherited)
407             } else {
408                 Ok(Visibility::Crate(VisCrate {
409                     crate_token: input.parse()?,
410                 }))
411             }
412         }
413 
414         #[cfg(feature = "full")]
is_some(&self) -> bool415         pub(crate) fn is_some(&self) -> bool {
416             match self {
417                 Visibility::Inherited => false,
418                 _ => true,
419             }
420         }
421     }
422 }
423 
424 #[cfg(feature = "printing")]
425 mod printing {
426     use super::*;
427     use crate::print::TokensOrDefault;
428     use proc_macro2::TokenStream;
429     use quote::{ToTokens, TokenStreamExt};
430 
431     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
432     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut TokenStream)433         fn to_tokens(&self, tokens: &mut TokenStream) {
434             tokens.append_all(&self.attrs);
435             self.ident.to_tokens(tokens);
436             self.fields.to_tokens(tokens);
437             if let Some((eq_token, disc)) = &self.discriminant {
438                 eq_token.to_tokens(tokens);
439                 disc.to_tokens(tokens);
440             }
441         }
442     }
443 
444     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
445     impl ToTokens for FieldsNamed {
to_tokens(&self, tokens: &mut TokenStream)446         fn to_tokens(&self, tokens: &mut TokenStream) {
447             self.brace_token.surround(tokens, |tokens| {
448                 self.named.to_tokens(tokens);
449             });
450         }
451     }
452 
453     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
454     impl ToTokens for FieldsUnnamed {
to_tokens(&self, tokens: &mut TokenStream)455         fn to_tokens(&self, tokens: &mut TokenStream) {
456             self.paren_token.surround(tokens, |tokens| {
457                 self.unnamed.to_tokens(tokens);
458             });
459         }
460     }
461 
462     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
463     impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)464         fn to_tokens(&self, tokens: &mut TokenStream) {
465             tokens.append_all(&self.attrs);
466             self.vis.to_tokens(tokens);
467             if let Some(ident) = &self.ident {
468                 ident.to_tokens(tokens);
469                 TokensOrDefault(&self.colon_token).to_tokens(tokens);
470             }
471             self.ty.to_tokens(tokens);
472         }
473     }
474 
475     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
476     impl ToTokens for VisPublic {
to_tokens(&self, tokens: &mut TokenStream)477         fn to_tokens(&self, tokens: &mut TokenStream) {
478             self.pub_token.to_tokens(tokens);
479         }
480     }
481 
482     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
483     impl ToTokens for VisCrate {
to_tokens(&self, tokens: &mut TokenStream)484         fn to_tokens(&self, tokens: &mut TokenStream) {
485             self.crate_token.to_tokens(tokens);
486         }
487     }
488 
489     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
490     impl ToTokens for VisRestricted {
to_tokens(&self, tokens: &mut TokenStream)491         fn to_tokens(&self, tokens: &mut TokenStream) {
492             self.pub_token.to_tokens(tokens);
493             self.paren_token.surround(tokens, |tokens| {
494                 // TODO: If we have a path which is not "self" or "super" or
495                 // "crate", automatically add the "in" token.
496                 self.in_token.to_tokens(tokens);
497                 self.path.to_tokens(tokens);
498             });
499         }
500     }
501 }
502