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. |
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 | 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 | |
154 | fn into_iter(self) -> Self::IntoIter { |
155 | match self { |
156 | Fields::Unit => Punctuated::<Field, ()>::new().into_iter(), |
157 | Fields::Named(f: FieldsNamed) => f.named.into_iter(), |
158 | Fields::Unnamed(f: FieldsUnnamed) => 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 | |
167 | 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 | |
176 | 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 | |
210 | fn next(&mut self) -> Option<Self::Item> { |
211 | let field: &'a Field = self.fields.next()?; |
212 | let member: Member = match &field.ident { |
213 | Some(ident: &Ident) => Member::Named(ident.clone()), |
214 | None => { |
215 | #[cfg (all(feature = "parsing" , feature = "printing" ))] |
216 | let span: 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> { |
231 | 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 { |
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 { |
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 { |
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" )))] |
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" )))] |
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 { |
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 { |
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 { |
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 { |
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 | |