• 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 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 
24 ast_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 
51 ast_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 
63 ast_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 
74 impl 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.
iter(&self) -> punctuated::Iter<Field>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.
iter_mut(&mut self) -> punctuated::IterMut<Field>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.
len(&self) -> usize98     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.
is_empty(&self) -> bool107     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 
116 impl IntoIterator for Fields {
117     type Item = Field;
118     type IntoIter = punctuated::IntoIter<Field>;
119 
into_iter(self) -> Self::IntoIter120     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 
129 impl<'a> IntoIterator for &'a Fields {
130     type Item = &'a Field;
131     type IntoIter = punctuated::Iter<'a, Field>;
132 
into_iter(self) -> Self::IntoIter133     fn into_iter(self) -> Self::IntoIter {
134         self.iter()
135     }
136 }
137 
138 impl<'a> IntoIterator for &'a mut Fields {
139     type Item = &'a mut Field;
140     type IntoIter = punctuated::IterMut<'a, Field>;
141 
into_iter(self) -> Self::IntoIter142     fn into_iter(self) -> Self::IntoIter {
143         self.iter_mut()
144     }
145 }
146 
147 ast_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 
171 ast_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 
202 ast_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 
212 ast_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 
222 ast_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")]
237 pub mod parsing {
238     use super::*;
239 
240     use crate::ext::IdentExt;
241     use crate::parse::{Parse, ParseStream, Result};
242 
243     impl Parse for Variant {
parse(input: ParseStream) -> Result<Self>244         fn parse(input: ParseStream) -> Result<Self> {
245             Ok(Variant {
246                 attrs: input.call(Attribute::parse_outer)?,
247                 ident: input.parse()?,
248                 fields: {
249                     if input.peek(token::Brace) {
250                         Fields::Named(input.parse()?)
251                     } else if input.peek(token::Paren) {
252                         Fields::Unnamed(input.parse()?)
253                     } else {
254                         Fields::Unit
255                     }
256                 },
257                 discriminant: {
258                     if input.peek(Token![=]) {
259                         let eq_token: Token![=] = input.parse()?;
260                         let discriminant: Expr = input.parse()?;
261                         Some((eq_token, discriminant))
262                     } else {
263                         None
264                     }
265                 },
266             })
267         }
268     }
269 
270     impl Parse for FieldsNamed {
parse(input: ParseStream) -> Result<Self>271         fn parse(input: ParseStream) -> Result<Self> {
272             let content;
273             Ok(FieldsNamed {
274                 brace_token: braced!(content in input),
275                 named: content.parse_terminated(Field::parse_named)?,
276             })
277         }
278     }
279 
280     impl Parse for FieldsUnnamed {
parse(input: ParseStream) -> Result<Self>281         fn parse(input: ParseStream) -> Result<Self> {
282             let content;
283             Ok(FieldsUnnamed {
284                 paren_token: parenthesized!(content in input),
285                 unnamed: content.parse_terminated(Field::parse_unnamed)?,
286             })
287         }
288     }
289 
290     impl Field {
291         /// Parses a named (braced struct) field.
parse_named(input: ParseStream) -> Result<Self>292         pub fn parse_named(input: ParseStream) -> Result<Self> {
293             Ok(Field {
294                 attrs: input.call(Attribute::parse_outer)?,
295                 vis: input.parse()?,
296                 ident: Some(input.parse()?),
297                 colon_token: Some(input.parse()?),
298                 ty: input.parse()?,
299             })
300         }
301 
302         /// Parses an unnamed (tuple struct) field.
parse_unnamed(input: ParseStream) -> Result<Self>303         pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
304             Ok(Field {
305                 attrs: input.call(Attribute::parse_outer)?,
306                 vis: input.parse()?,
307                 ident: None,
308                 colon_token: None,
309                 ty: input.parse()?,
310             })
311         }
312     }
313 
314     impl Parse for Visibility {
parse(input: ParseStream) -> Result<Self>315         fn parse(input: ParseStream) -> Result<Self> {
316             if input.peek(Token![pub]) {
317                 Self::parse_pub(input)
318             } else if input.peek(Token![crate]) {
319                 Self::parse_crate(input)
320             } else {
321                 Ok(Visibility::Inherited)
322             }
323         }
324     }
325 
326     impl Visibility {
parse_pub(input: ParseStream) -> Result<Self>327         fn parse_pub(input: ParseStream) -> Result<Self> {
328             let pub_token = input.parse::<Token![pub]>()?;
329 
330             if input.peek(token::Paren) {
331                 // TODO: optimize using advance_to
332                 let ahead = input.fork();
333                 let mut content;
334                 parenthesized!(content in ahead);
335 
336                 if content.peek(Token![crate])
337                     || content.peek(Token![self])
338                     || content.peek(Token![super])
339                 {
340                     return Ok(Visibility::Restricted(VisRestricted {
341                         pub_token,
342                         paren_token: parenthesized!(content in input),
343                         in_token: None,
344                         path: Box::new(Path::from(content.call(Ident::parse_any)?)),
345                     }));
346                 } else if content.peek(Token![in]) {
347                     return Ok(Visibility::Restricted(VisRestricted {
348                         pub_token,
349                         paren_token: parenthesized!(content in input),
350                         in_token: Some(content.parse()?),
351                         path: Box::new(content.call(Path::parse_mod_style)?),
352                     }));
353                 }
354             }
355 
356             Ok(Visibility::Public(VisPublic { pub_token }))
357         }
358 
parse_crate(input: ParseStream) -> Result<Self>359         fn parse_crate(input: ParseStream) -> Result<Self> {
360             if input.peek2(Token![::]) {
361                 Ok(Visibility::Inherited)
362             } else {
363                 Ok(Visibility::Crate(VisCrate {
364                     crate_token: input.parse()?,
365                 }))
366             }
367         }
368     }
369 }
370 
371 #[cfg(feature = "printing")]
372 mod printing {
373     use super::*;
374 
375     use proc_macro2::TokenStream;
376     use quote::{ToTokens, TokenStreamExt};
377 
378     use crate::print::TokensOrDefault;
379 
380     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut TokenStream)381         fn to_tokens(&self, tokens: &mut TokenStream) {
382             tokens.append_all(&self.attrs);
383             self.ident.to_tokens(tokens);
384             self.fields.to_tokens(tokens);
385             if let Some((eq_token, disc)) = &self.discriminant {
386                 eq_token.to_tokens(tokens);
387                 disc.to_tokens(tokens);
388             }
389         }
390     }
391 
392     impl ToTokens for FieldsNamed {
to_tokens(&self, tokens: &mut TokenStream)393         fn to_tokens(&self, tokens: &mut TokenStream) {
394             self.brace_token.surround(tokens, |tokens| {
395                 self.named.to_tokens(tokens);
396             });
397         }
398     }
399 
400     impl ToTokens for FieldsUnnamed {
to_tokens(&self, tokens: &mut TokenStream)401         fn to_tokens(&self, tokens: &mut TokenStream) {
402             self.paren_token.surround(tokens, |tokens| {
403                 self.unnamed.to_tokens(tokens);
404             });
405         }
406     }
407 
408     impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)409         fn to_tokens(&self, tokens: &mut TokenStream) {
410             tokens.append_all(&self.attrs);
411             self.vis.to_tokens(tokens);
412             if let Some(ident) = &self.ident {
413                 ident.to_tokens(tokens);
414                 TokensOrDefault(&self.colon_token).to_tokens(tokens);
415             }
416             self.ty.to_tokens(tokens);
417         }
418     }
419 
420     impl ToTokens for VisPublic {
to_tokens(&self, tokens: &mut TokenStream)421         fn to_tokens(&self, tokens: &mut TokenStream) {
422             self.pub_token.to_tokens(tokens)
423         }
424     }
425 
426     impl ToTokens for VisCrate {
to_tokens(&self, tokens: &mut TokenStream)427         fn to_tokens(&self, tokens: &mut TokenStream) {
428             self.crate_token.to_tokens(tokens);
429         }
430     }
431 
432     impl ToTokens for VisRestricted {
to_tokens(&self, tokens: &mut TokenStream)433         fn to_tokens(&self, tokens: &mut TokenStream) {
434             self.pub_token.to_tokens(tokens);
435             self.paren_token.surround(tokens, |tokens| {
436                 // TODO: If we have a path which is not "self" or "super" or
437                 // "crate", automatically add the "in" token.
438                 self.in_token.to_tokens(tokens);
439                 self.path.to_tokens(tokens);
440             });
441         }
442     }
443 }
444