• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::punctuated::Punctuated;
3 
4 ast_struct! {
5     /// An enum variant.
6     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
7     pub struct Variant {
8         pub attrs: Vec<Attribute>,
9 
10         /// Name of the variant.
11         pub ident: Ident,
12 
13         /// Content stored in the variant.
14         pub fields: Fields,
15 
16         /// Explicit discriminant: `Variant = 1`
17         pub discriminant: Option<(Token![=], Expr)>,
18     }
19 }
20 
21 ast_enum_of_structs! {
22     /// Data stored within an enum variant or struct.
23     ///
24     /// # Syntax tree enum
25     ///
26     /// This type is a [syntax tree enum].
27     ///
28     /// [syntax tree enum]: Expr#syntax-tree-enums
29     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
30     pub enum Fields {
31         /// Named fields of a struct or struct variant such as `Point { x: f64,
32         /// y: f64 }`.
33         Named(FieldsNamed),
34 
35         /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
36         Unnamed(FieldsUnnamed),
37 
38         /// Unit struct or unit variant such as `None`.
39         Unit,
40     }
41 }
42 
43 ast_struct! {
44     /// Named fields of a struct or struct variant such as `Point { x: f64,
45     /// y: f64 }`.
46     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
47     pub struct FieldsNamed {
48         pub brace_token: token::Brace,
49         pub named: Punctuated<Field, Token![,]>,
50     }
51 }
52 
53 ast_struct! {
54     /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
55     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
56     pub struct FieldsUnnamed {
57         pub paren_token: token::Paren,
58         pub unnamed: Punctuated<Field, Token![,]>,
59     }
60 }
61 
62 impl Fields {
63     /// Get an iterator over the borrowed [`Field`] items in this object. This
64     /// iterator can be used to iterate over a named or unnamed struct or
65     /// variant's fields uniformly.
iter(&self) -> punctuated::Iter<Field>66     pub fn iter(&self) -> punctuated::Iter<Field> {
67         match self {
68             Fields::Unit => crate::punctuated::empty_punctuated_iter(),
69             Fields::Named(f) => f.named.iter(),
70             Fields::Unnamed(f) => f.unnamed.iter(),
71         }
72     }
73 
74     /// Get an iterator over the mutably borrowed [`Field`] items in this
75     /// object. This iterator can be used to iterate over a named or unnamed
76     /// struct or variant's fields uniformly.
iter_mut(&mut self) -> punctuated::IterMut<Field>77     pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
78         match self {
79             Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(),
80             Fields::Named(f) => f.named.iter_mut(),
81             Fields::Unnamed(f) => f.unnamed.iter_mut(),
82         }
83     }
84 
85     /// Returns the number of fields.
len(&self) -> usize86     pub fn len(&self) -> usize {
87         match self {
88             Fields::Unit => 0,
89             Fields::Named(f) => f.named.len(),
90             Fields::Unnamed(f) => f.unnamed.len(),
91         }
92     }
93 
94     /// Returns `true` if there are zero fields.
is_empty(&self) -> bool95     pub fn is_empty(&self) -> bool {
96         match self {
97             Fields::Unit => true,
98             Fields::Named(f) => f.named.is_empty(),
99             Fields::Unnamed(f) => f.unnamed.is_empty(),
100         }
101     }
102 }
103 
104 impl IntoIterator for Fields {
105     type Item = Field;
106     type IntoIter = punctuated::IntoIter<Field>;
107 
into_iter(self) -> Self::IntoIter108     fn into_iter(self) -> Self::IntoIter {
109         match self {
110             Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
111             Fields::Named(f) => f.named.into_iter(),
112             Fields::Unnamed(f) => f.unnamed.into_iter(),
113         }
114     }
115 }
116 
117 impl<'a> IntoIterator for &'a Fields {
118     type Item = &'a Field;
119     type IntoIter = punctuated::Iter<'a, Field>;
120 
into_iter(self) -> Self::IntoIter121     fn into_iter(self) -> Self::IntoIter {
122         self.iter()
123     }
124 }
125 
126 impl<'a> IntoIterator for &'a mut Fields {
127     type Item = &'a mut Field;
128     type IntoIter = punctuated::IterMut<'a, Field>;
129 
into_iter(self) -> Self::IntoIter130     fn into_iter(self) -> Self::IntoIter {
131         self.iter_mut()
132     }
133 }
134 
135 ast_struct! {
136     /// A field of a struct or enum variant.
137     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
138     pub struct Field {
139         pub attrs: Vec<Attribute>,
140 
141         pub vis: Visibility,
142 
143         pub mutability: FieldMutability,
144 
145         /// Name of the field, if any.
146         ///
147         /// Fields of tuple structs have no names.
148         pub ident: Option<Ident>,
149 
150         pub colon_token: Option<Token![:]>,
151 
152         pub ty: Type,
153     }
154 }
155 
156 #[cfg(feature = "parsing")]
157 pub(crate) mod parsing {
158     use super::*;
159     use crate::ext::IdentExt as _;
160     #[cfg(not(feature = "full"))]
161     use crate::parse::discouraged::Speculative as _;
162     use crate::parse::{Parse, ParseStream, Result};
163 
164     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
165     impl Parse for Variant {
parse(input: ParseStream) -> Result<Self>166         fn parse(input: ParseStream) -> Result<Self> {
167             let attrs = input.call(Attribute::parse_outer)?;
168             let _visibility: Visibility = input.parse()?;
169             let ident: Ident = input.parse()?;
170             let fields = if input.peek(token::Brace) {
171                 Fields::Named(input.parse()?)
172             } else if input.peek(token::Paren) {
173                 Fields::Unnamed(input.parse()?)
174             } else {
175                 Fields::Unit
176             };
177             let discriminant = if input.peek(Token![=]) {
178                 let eq_token: Token![=] = input.parse()?;
179                 #[cfg(feature = "full")]
180                 let discriminant: Expr = input.parse()?;
181                 #[cfg(not(feature = "full"))]
182                 let discriminant = {
183                     let begin = input.fork();
184                     let ahead = input.fork();
185                     let mut discriminant: Result<Expr> = ahead.parse();
186                     if discriminant.is_ok() {
187                         input.advance_to(&ahead);
188                     } else if scan_lenient_discriminant(input).is_ok() {
189                         discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input)));
190                     }
191                     discriminant?
192                 };
193                 Some((eq_token, discriminant))
194             } else {
195                 None
196             };
197             Ok(Variant {
198                 attrs,
199                 ident,
200                 fields,
201                 discriminant,
202             })
203         }
204     }
205 
206     #[cfg(not(feature = "full"))]
scan_lenient_discriminant(input: ParseStream) -> Result<()>207     pub(crate) fn scan_lenient_discriminant(input: ParseStream) -> Result<()> {
208         use proc_macro2::Delimiter::{self, Brace, Bracket, Parenthesis};
209 
210         let consume = |delimiter: Delimiter| {
211             Result::unwrap(input.step(|cursor| match cursor.group(delimiter) {
212                 Some((_inside, _span, rest)) => Ok((true, rest)),
213                 None => Ok((false, *cursor)),
214             }))
215         };
216 
217         macro_rules! consume {
218             [$token:tt] => {
219                 input.parse::<Option<Token![$token]>>().unwrap().is_some()
220             };
221         }
222 
223         let mut initial = true;
224         let mut depth = 0usize;
225         loop {
226             if initial {
227                 if consume![&] {
228                     input.parse::<Option<Token![mut]>>()?;
229                 } else if consume![if] || consume![match] || consume![while] {
230                     depth += 1;
231                 } else if input.parse::<Option<Lit>>()?.is_some()
232                     || (consume(Brace) || consume(Bracket) || consume(Parenthesis))
233                     || (consume![async] || consume![const] || consume![loop] || consume![unsafe])
234                         && (consume(Brace) || break)
235                 {
236                     initial = false;
237                 } else if consume![let] {
238                     while !consume![=] {
239                         if !((consume![|] || consume![ref] || consume![mut] || consume![@])
240                             || (consume![!] || input.parse::<Option<Lit>>()?.is_some())
241                             || (consume![..=] || consume![..] || consume![&] || consume![_])
242                             || (consume(Brace) || consume(Bracket) || consume(Parenthesis)))
243                         {
244                             path::parsing::qpath(input, true)?;
245                         }
246                     }
247                 } else if input.parse::<Option<Lifetime>>()?.is_some() && !consume![:] {
248                     break;
249                 } else if input.parse::<UnOp>().is_err() {
250                     path::parsing::qpath(input, true)?;
251                     initial = consume![!] || depth == 0 && input.peek(token::Brace);
252                 }
253             } else if input.is_empty() || input.peek(Token![,]) {
254                 return Ok(());
255             } else if depth > 0 && consume(Brace) {
256                 if consume![else] && !consume(Brace) {
257                     initial = consume![if] || break;
258                 } else {
259                     depth -= 1;
260                 }
261             } else if input.parse::<BinOp>().is_ok() || (consume![..] | consume![=]) {
262                 initial = true;
263             } else if consume![.] {
264                 if input.parse::<Option<LitFloat>>()?.is_none()
265                     && (input.parse::<Member>()?.is_named() && consume![::])
266                 {
267                     AngleBracketedGenericArguments::do_parse(None, input)?;
268                 }
269             } else if consume![as] {
270                 input.parse::<Type>()?;
271             } else if !(consume(Brace) || consume(Bracket) || consume(Parenthesis)) {
272                 break;
273             }
274         }
275 
276         Err(input.error("unsupported expression"))
277     }
278 
279     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
280     impl Parse for FieldsNamed {
parse(input: ParseStream) -> Result<Self>281         fn parse(input: ParseStream) -> Result<Self> {
282             let content;
283             Ok(FieldsNamed {
284                 brace_token: braced!(content in input),
285                 named: content.parse_terminated(Field::parse_named, Token![,])?,
286             })
287         }
288     }
289 
290     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
291     impl Parse for FieldsUnnamed {
parse(input: ParseStream) -> Result<Self>292         fn parse(input: ParseStream) -> Result<Self> {
293             let content;
294             Ok(FieldsUnnamed {
295                 paren_token: parenthesized!(content in input),
296                 unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?,
297             })
298         }
299     }
300 
301     impl Field {
302         /// Parses a named (braced struct) field.
303         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_named(input: ParseStream) -> Result<Self>304         pub fn parse_named(input: ParseStream) -> Result<Self> {
305             let attrs = input.call(Attribute::parse_outer)?;
306             let vis: Visibility = input.parse()?;
307 
308             let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]);
309             let ident = if unnamed_field {
310                 input.call(Ident::parse_any)
311             } else {
312                 input.parse()
313             }?;
314 
315             let colon_token: Token![:] = input.parse()?;
316 
317             let ty: Type = if unnamed_field
318                 && (input.peek(Token![struct])
319                     || input.peek(Token![union]) && input.peek2(token::Brace))
320             {
321                 let begin = input.fork();
322                 input.call(Ident::parse_any)?;
323                 input.parse::<FieldsNamed>()?;
324                 Type::Verbatim(verbatim::between(&begin, input))
325             } else {
326                 input.parse()?
327             };
328 
329             Ok(Field {
330                 attrs,
331                 vis,
332                 mutability: FieldMutability::None,
333                 ident: Some(ident),
334                 colon_token: Some(colon_token),
335                 ty,
336             })
337         }
338 
339         /// Parses an unnamed (tuple struct) field.
340         #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_unnamed(input: ParseStream) -> Result<Self>341         pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
342             Ok(Field {
343                 attrs: input.call(Attribute::parse_outer)?,
344                 vis: input.parse()?,
345                 mutability: FieldMutability::None,
346                 ident: None,
347                 colon_token: None,
348                 ty: input.parse()?,
349             })
350         }
351     }
352 }
353 
354 #[cfg(feature = "printing")]
355 mod printing {
356     use super::*;
357     use crate::print::TokensOrDefault;
358     use proc_macro2::TokenStream;
359     use quote::{ToTokens, TokenStreamExt};
360 
361     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
362     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut TokenStream)363         fn to_tokens(&self, tokens: &mut TokenStream) {
364             tokens.append_all(&self.attrs);
365             self.ident.to_tokens(tokens);
366             self.fields.to_tokens(tokens);
367             if let Some((eq_token, disc)) = &self.discriminant {
368                 eq_token.to_tokens(tokens);
369                 disc.to_tokens(tokens);
370             }
371         }
372     }
373 
374     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
375     impl ToTokens for FieldsNamed {
to_tokens(&self, tokens: &mut TokenStream)376         fn to_tokens(&self, tokens: &mut TokenStream) {
377             self.brace_token.surround(tokens, |tokens| {
378                 self.named.to_tokens(tokens);
379             });
380         }
381     }
382 
383     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
384     impl ToTokens for FieldsUnnamed {
to_tokens(&self, tokens: &mut TokenStream)385         fn to_tokens(&self, tokens: &mut TokenStream) {
386             self.paren_token.surround(tokens, |tokens| {
387                 self.unnamed.to_tokens(tokens);
388             });
389         }
390     }
391 
392     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
393     impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)394         fn to_tokens(&self, tokens: &mut TokenStream) {
395             tokens.append_all(&self.attrs);
396             self.vis.to_tokens(tokens);
397             if let Some(ident) = &self.ident {
398                 ident.to_tokens(tokens);
399                 TokensOrDefault(&self.colon_token).to_tokens(tokens);
400             }
401             self.ty.to_tokens(tokens);
402         }
403     }
404 }
405