• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 {
parse(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>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")))]
parse_named(input: ParseStream) -> Result<Self>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")))]
parse_unnamed(input: ParseStream) -> Result<Self>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 {
parse(input: ParseStream) -> Result<Self>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 {
parse_pub(input: ParseStream) -> Result<Self>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 
parse_crate(input: ParseStream) -> Result<Self>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")]
is_some(&self) -> bool407         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")]
417 mod 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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 {
to_tokens(&self, tokens: &mut TokenStream)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 }
494