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(if input.peek(Token![_]) {
317                     input.call(Ident::parse_any)
318                 } else {
319                     input.parse()
320                 }?),
321                 colon_token: Some(input.parse()?),
322                 ty: input.parse()?,
323             })
324         }
325 
326         /// Parses an unnamed (tuple struct) field.
327         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_unnamed(input: ParseStream) -> Result<Self>328         pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
329             Ok(Field {
330                 attrs: input.call(Attribute::parse_outer)?,
331                 vis: input.parse()?,
332                 ident: None,
333                 colon_token: None,
334                 ty: input.parse()?,
335             })
336         }
337     }
338 
339     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
340     impl Parse for Visibility {
parse(input: ParseStream) -> Result<Self>341         fn parse(input: ParseStream) -> Result<Self> {
342             // Recognize an empty None-delimited group, as produced by a $:vis
343             // matcher that matched no tokens.
344             if input.peek(token::Group) {
345                 let ahead = input.fork();
346                 let group = crate::group::parse_group(&ahead)?;
347                 if group.content.is_empty() {
348                     input.advance_to(&ahead);
349                     return Ok(Visibility::Inherited);
350                 }
351             }
352 
353             if input.peek(Token![pub]) {
354                 Self::parse_pub(input)
355             } else if input.peek(Token![crate]) {
356                 Self::parse_crate(input)
357             } else {
358                 Ok(Visibility::Inherited)
359             }
360         }
361     }
362 
363     impl Visibility {
parse_pub(input: ParseStream) -> Result<Self>364         fn parse_pub(input: ParseStream) -> Result<Self> {
365             let pub_token = input.parse::<Token![pub]>()?;
366 
367             if input.peek(token::Paren) {
368                 let ahead = input.fork();
369 
370                 let content;
371                 let paren_token = parenthesized!(content in ahead);
372                 if content.peek(Token![crate])
373                     || content.peek(Token![self])
374                     || content.peek(Token![super])
375                 {
376                     let path = content.call(Ident::parse_any)?;
377 
378                     // Ensure there are no additional tokens within `content`.
379                     // Without explicitly checking, we may misinterpret a tuple
380                     // field as a restricted visibility, causing a parse error.
381                     // e.g. `pub (crate::A, crate::B)` (Issue #720).
382                     if content.is_empty() {
383                         input.advance_to(&ahead);
384                         return Ok(Visibility::Restricted(VisRestricted {
385                             pub_token,
386                             paren_token,
387                             in_token: None,
388                             path: Box::new(Path::from(path)),
389                         }));
390                     }
391                 } else if content.peek(Token![in]) {
392                     let in_token: Token![in] = content.parse()?;
393                     let path = content.call(Path::parse_mod_style)?;
394 
395                     input.advance_to(&ahead);
396                     return Ok(Visibility::Restricted(VisRestricted {
397                         pub_token,
398                         paren_token,
399                         in_token: Some(in_token),
400                         path: Box::new(path),
401                     }));
402                 }
403             }
404 
405             Ok(Visibility::Public(VisPublic { pub_token }))
406         }
407 
parse_crate(input: ParseStream) -> Result<Self>408         fn parse_crate(input: ParseStream) -> Result<Self> {
409             if input.peek2(Token![::]) {
410                 Ok(Visibility::Inherited)
411             } else {
412                 Ok(Visibility::Crate(VisCrate {
413                     crate_token: input.parse()?,
414                 }))
415             }
416         }
417 
418         #[cfg(feature = "full")]
is_some(&self) -> bool419         pub(crate) fn is_some(&self) -> bool {
420             match self {
421                 Visibility::Inherited => false,
422                 _ => true,
423             }
424         }
425     }
426 }
427 
428 #[cfg(feature = "printing")]
429 mod printing {
430     use super::*;
431     use crate::print::TokensOrDefault;
432     use proc_macro2::TokenStream;
433     use quote::{ToTokens, TokenStreamExt};
434 
435     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
436     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut TokenStream)437         fn to_tokens(&self, tokens: &mut TokenStream) {
438             tokens.append_all(&self.attrs);
439             self.ident.to_tokens(tokens);
440             self.fields.to_tokens(tokens);
441             if let Some((eq_token, disc)) = &self.discriminant {
442                 eq_token.to_tokens(tokens);
443                 disc.to_tokens(tokens);
444             }
445         }
446     }
447 
448     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
449     impl ToTokens for FieldsNamed {
to_tokens(&self, tokens: &mut TokenStream)450         fn to_tokens(&self, tokens: &mut TokenStream) {
451             self.brace_token.surround(tokens, |tokens| {
452                 self.named.to_tokens(tokens);
453             });
454         }
455     }
456 
457     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
458     impl ToTokens for FieldsUnnamed {
to_tokens(&self, tokens: &mut TokenStream)459         fn to_tokens(&self, tokens: &mut TokenStream) {
460             self.paren_token.surround(tokens, |tokens| {
461                 self.unnamed.to_tokens(tokens);
462             });
463         }
464     }
465 
466     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
467     impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)468         fn to_tokens(&self, tokens: &mut TokenStream) {
469             tokens.append_all(&self.attrs);
470             self.vis.to_tokens(tokens);
471             if let Some(ident) = &self.ident {
472                 ident.to_tokens(tokens);
473                 TokensOrDefault(&self.colon_token).to_tokens(tokens);
474             }
475             self.ty.to_tokens(tokens);
476         }
477     }
478 
479     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
480     impl ToTokens for VisPublic {
to_tokens(&self, tokens: &mut TokenStream)481         fn to_tokens(&self, tokens: &mut TokenStream) {
482             self.pub_token.to_tokens(tokens);
483         }
484     }
485 
486     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
487     impl ToTokens for VisCrate {
to_tokens(&self, tokens: &mut TokenStream)488         fn to_tokens(&self, tokens: &mut TokenStream) {
489             self.crate_token.to_tokens(tokens);
490         }
491     }
492 
493     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
494     impl ToTokens for VisRestricted {
to_tokens(&self, tokens: &mut TokenStream)495         fn to_tokens(&self, tokens: &mut TokenStream) {
496             self.pub_token.to_tokens(tokens);
497             self.paren_token.surround(tokens, |tokens| {
498                 // TODO: If we have a path which is not "self" or "super" or
499                 // "crate", automatically add the "in" token.
500                 self.in_token.to_tokens(tokens);
501                 self.path.to_tokens(tokens);
502             });
503         }
504     }
505 }
506