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