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