• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::attr::Attribute;
2 use crate::expr::{Expr, Index, Member};
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(docsrs, 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(docsrs, 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(docsrs, 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(docsrs, 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.
iter(&self) -> punctuated::Iter<Field>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.
iter_mut(&mut self) -> punctuated::IterMut<Field>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.
len(&self) -> usize91     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.
is_empty(&self) -> bool100     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     return_impl_trait! {
109         /// Get an iterator over the fields of a struct or variant as [`Member`]s.
110         /// This iterator can be used to iterate over a named or unnamed struct or
111         /// variant's fields uniformly.
112         ///
113         /// # Example
114         ///
115         /// The following is a simplistic [`Clone`] derive for structs. (A more
116         /// complete implementation would additionally want to infer trait bounds on
117         /// the generic type parameters.)
118         ///
119         /// ```
120         /// # use quote::quote;
121         /// #
122         /// fn derive_clone(input: &syn::ItemStruct) -> proc_macro2::TokenStream {
123         ///     let ident = &input.ident;
124         ///     let members = input.fields.members();
125         ///     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
126         ///     quote! {
127         ///         impl #impl_generics Clone for #ident #ty_generics #where_clause {
128         ///             fn clone(&self) -> Self {
129         ///                 Self {
130         ///                     #(#members: self.#members.clone()),*
131         ///                 }
132         ///             }
133         ///         }
134         ///     }
135         /// }
136         /// ```
137         ///
138         /// For structs with named fields, it produces an expression like `Self { a:
139         /// self.a.clone() }`. For structs with unnamed fields, `Self { 0:
140         /// self.0.clone() }`. And for unit structs, `Self {}`.
141         pub fn members(&self) -> impl Iterator<Item = Member> + Clone + '_ [Members] {
142             Members {
143                 fields: self.iter(),
144                 index: 0,
145             }
146         }
147     }
148 }
149 
150 impl IntoIterator for Fields {
151     type Item = Field;
152     type IntoIter = punctuated::IntoIter<Field>;
153 
into_iter(self) -> Self::IntoIter154     fn into_iter(self) -> Self::IntoIter {
155         match self {
156             Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
157             Fields::Named(f) => f.named.into_iter(),
158             Fields::Unnamed(f) => f.unnamed.into_iter(),
159         }
160     }
161 }
162 
163 impl<'a> IntoIterator for &'a Fields {
164     type Item = &'a Field;
165     type IntoIter = punctuated::Iter<'a, Field>;
166 
into_iter(self) -> Self::IntoIter167     fn into_iter(self) -> Self::IntoIter {
168         self.iter()
169     }
170 }
171 
172 impl<'a> IntoIterator for &'a mut Fields {
173     type Item = &'a mut Field;
174     type IntoIter = punctuated::IterMut<'a, Field>;
175 
into_iter(self) -> Self::IntoIter176     fn into_iter(self) -> Self::IntoIter {
177         self.iter_mut()
178     }
179 }
180 
181 ast_struct! {
182     /// A field of a struct or enum variant.
183     #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
184     pub struct Field {
185         pub attrs: Vec<Attribute>,
186 
187         pub vis: Visibility,
188 
189         pub mutability: FieldMutability,
190 
191         /// Name of the field, if any.
192         ///
193         /// Fields of tuple structs have no names.
194         pub ident: Option<Ident>,
195 
196         pub colon_token: Option<Token![:]>,
197 
198         pub ty: Type,
199     }
200 }
201 
202 pub struct Members<'a> {
203     fields: punctuated::Iter<'a, Field>,
204     index: u32,
205 }
206 
207 impl<'a> Iterator for Members<'a> {
208     type Item = Member;
209 
next(&mut self) -> Option<Self::Item>210     fn next(&mut self) -> Option<Self::Item> {
211         let field = self.fields.next()?;
212         let member = match &field.ident {
213             Some(ident) => Member::Named(ident.clone()),
214             None => {
215                 #[cfg(all(feature = "parsing", feature = "printing"))]
216                 let span = crate::spanned::Spanned::span(&field.ty);
217                 #[cfg(not(all(feature = "parsing", feature = "printing")))]
218                 let span = proc_macro2::Span::call_site();
219                 Member::Unnamed(Index {
220                     index: self.index,
221                     span,
222                 })
223             }
224         };
225         self.index += 1;
226         Some(member)
227     }
228 }
229 
230 impl<'a> Clone for Members<'a> {
clone(&self) -> Self231     fn clone(&self) -> Self {
232         Members {
233             fields: self.fields.clone(),
234             index: self.index,
235         }
236     }
237 }
238 
239 #[cfg(feature = "parsing")]
240 pub(crate) mod parsing {
241     use crate::attr::Attribute;
242     use crate::data::{Field, Fields, FieldsNamed, FieldsUnnamed, Variant};
243     use crate::error::Result;
244     use crate::expr::Expr;
245     use crate::ext::IdentExt as _;
246     use crate::ident::Ident;
247     #[cfg(not(feature = "full"))]
248     use crate::parse::discouraged::Speculative as _;
249     use crate::parse::{Parse, ParseStream};
250     use crate::restriction::{FieldMutability, Visibility};
251     #[cfg(not(feature = "full"))]
252     use crate::scan_expr::scan_expr;
253     use crate::token;
254     use crate::ty::Type;
255     use crate::verbatim;
256 
257     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
258     impl Parse for Variant {
parse(input: ParseStream) -> Result<Self>259         fn parse(input: ParseStream) -> Result<Self> {
260             let attrs = input.call(Attribute::parse_outer)?;
261             let _visibility: Visibility = input.parse()?;
262             let ident: Ident = input.parse()?;
263             let fields = if input.peek(token::Brace) {
264                 Fields::Named(input.parse()?)
265             } else if input.peek(token::Paren) {
266                 Fields::Unnamed(input.parse()?)
267             } else {
268                 Fields::Unit
269             };
270             let discriminant = if input.peek(Token![=]) {
271                 let eq_token: Token![=] = input.parse()?;
272                 #[cfg(feature = "full")]
273                 let discriminant: Expr = input.parse()?;
274                 #[cfg(not(feature = "full"))]
275                 let discriminant = {
276                     let begin = input.fork();
277                     let ahead = input.fork();
278                     let mut discriminant: Result<Expr> = ahead.parse();
279                     if discriminant.is_ok() {
280                         input.advance_to(&ahead);
281                     } else if scan_expr(input).is_ok() {
282                         discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input)));
283                     }
284                     discriminant?
285                 };
286                 Some((eq_token, discriminant))
287             } else {
288                 None
289             };
290             Ok(Variant {
291                 attrs,
292                 ident,
293                 fields,
294                 discriminant,
295             })
296         }
297     }
298 
299     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
300     impl Parse for FieldsNamed {
parse(input: ParseStream) -> Result<Self>301         fn parse(input: ParseStream) -> Result<Self> {
302             let content;
303             Ok(FieldsNamed {
304                 brace_token: braced!(content in input),
305                 named: content.parse_terminated(Field::parse_named, Token![,])?,
306             })
307         }
308     }
309 
310     #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
311     impl Parse for FieldsUnnamed {
parse(input: ParseStream) -> Result<Self>312         fn parse(input: ParseStream) -> Result<Self> {
313             let content;
314             Ok(FieldsUnnamed {
315                 paren_token: parenthesized!(content in input),
316                 unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?,
317             })
318         }
319     }
320 
321     impl Field {
322         /// Parses a named (braced struct) field.
323         #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse_named(input: ParseStream) -> Result<Self>324         pub fn parse_named(input: ParseStream) -> Result<Self> {
325             let attrs = input.call(Attribute::parse_outer)?;
326             let vis: Visibility = input.parse()?;
327 
328             let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]);
329             let ident = if unnamed_field {
330                 input.call(Ident::parse_any)
331             } else {
332                 input.parse()
333             }?;
334 
335             let colon_token: Token![:] = input.parse()?;
336 
337             let ty: Type = if unnamed_field
338                 && (input.peek(Token![struct])
339                     || input.peek(Token![union]) && input.peek2(token::Brace))
340             {
341                 let begin = input.fork();
342                 input.call(Ident::parse_any)?;
343                 input.parse::<FieldsNamed>()?;
344                 Type::Verbatim(verbatim::between(&begin, input))
345             } else {
346                 input.parse()?
347             };
348 
349             Ok(Field {
350                 attrs,
351                 vis,
352                 mutability: FieldMutability::None,
353                 ident: Some(ident),
354                 colon_token: Some(colon_token),
355                 ty,
356             })
357         }
358 
359         /// Parses an unnamed (tuple struct) field.
360         #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
parse_unnamed(input: ParseStream) -> Result<Self>361         pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
362             Ok(Field {
363                 attrs: input.call(Attribute::parse_outer)?,
364                 vis: input.parse()?,
365                 mutability: FieldMutability::None,
366                 ident: None,
367                 colon_token: None,
368                 ty: input.parse()?,
369             })
370         }
371     }
372 }
373 
374 #[cfg(feature = "printing")]
375 mod printing {
376     use crate::data::{Field, FieldsNamed, FieldsUnnamed, Variant};
377     use crate::print::TokensOrDefault;
378     use proc_macro2::TokenStream;
379     use quote::{ToTokens, TokenStreamExt};
380 
381     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
382     impl ToTokens for Variant {
to_tokens(&self, tokens: &mut TokenStream)383         fn to_tokens(&self, tokens: &mut TokenStream) {
384             tokens.append_all(&self.attrs);
385             self.ident.to_tokens(tokens);
386             self.fields.to_tokens(tokens);
387             if let Some((eq_token, disc)) = &self.discriminant {
388                 eq_token.to_tokens(tokens);
389                 disc.to_tokens(tokens);
390             }
391         }
392     }
393 
394     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
395     impl ToTokens for FieldsNamed {
to_tokens(&self, tokens: &mut TokenStream)396         fn to_tokens(&self, tokens: &mut TokenStream) {
397             self.brace_token.surround(tokens, |tokens| {
398                 self.named.to_tokens(tokens);
399             });
400         }
401     }
402 
403     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
404     impl ToTokens for FieldsUnnamed {
to_tokens(&self, tokens: &mut TokenStream)405         fn to_tokens(&self, tokens: &mut TokenStream) {
406             self.paren_token.surround(tokens, |tokens| {
407                 self.unnamed.to_tokens(tokens);
408             });
409         }
410     }
411 
412     #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
413     impl ToTokens for Field {
to_tokens(&self, tokens: &mut TokenStream)414         fn to_tokens(&self, tokens: &mut TokenStream) {
415             tokens.append_all(&self.attrs);
416             self.vis.to_tokens(tokens);
417             if let Some(ident) = &self.ident {
418                 ident.to_tokens(tokens);
419                 TokensOrDefault(&self.colon_token).to_tokens(tokens);
420             }
421             self.ty.to_tokens(tokens);
422         }
423     }
424 }
425