1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_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
21ast_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
43ast_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
53ast_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
62impl 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.
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.
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.
86 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.
95 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
104impl IntoIterator for Fields {
105 type Item = Field;
106 type IntoIter = punctuated::IntoIter<Field>;
107
108 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
117impl<'a> IntoIterator for &'a Fields {
118 type Item = &'a Field;
119 type IntoIter = punctuated::Iter<'a, Field>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 self.iter()
123 }
124}
125
126impl<'a> IntoIterator for &'a mut Fields {
127 type Item = &'a mut Field;
128 type IntoIter = punctuated::IterMut<'a, Field>;
129
130 fn into_iter(self) -> Self::IntoIter {
131 self.iter_mut()
132 }
133}
134
135ast_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")]
157pub(crate) mod parsing {
158 use super::*;
159 use crate::ext::IdentExt;
160 use crate::parse::{Parse, ParseStream, Result};
161
162 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
163 impl Parse for Variant {
164 fn parse(input: ParseStream) -> Result<Self> {
165 let attrs = input.call(Attribute::parse_outer)?;
166 let _visibility: Visibility = input.parse()?;
167 let ident: Ident = input.parse()?;
168 let fields = if input.peek(token::Brace) {
169 Fields::Named(input.parse()?)
170 } else if input.peek(token::Paren) {
171 Fields::Unnamed(input.parse()?)
172 } else {
173 Fields::Unit
174 };
175 let discriminant = if input.peek(Token![=]) {
176 let eq_token: Token![=] = input.parse()?;
177 let discriminant: Expr = input.parse()?;
178 Some((eq_token, discriminant))
179 } else {
180 None
181 };
182 Ok(Variant {
183 attrs,
184 ident,
185 fields,
186 discriminant,
187 })
188 }
189 }
190
191 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
192 impl Parse for FieldsNamed {
193 fn parse(input: ParseStream) -> Result<Self> {
194 let content;
195 Ok(FieldsNamed {
196 brace_token: braced!(content in input),
197 named: content.parse_terminated(Field::parse_named, Token![,])?,
198 })
199 }
200 }
201
202 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
203 impl Parse for FieldsUnnamed {
204 fn parse(input: ParseStream) -> Result<Self> {
205 let content;
206 Ok(FieldsUnnamed {
207 paren_token: parenthesized!(content in input),
208 unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?,
209 })
210 }
211 }
212
213 impl Field {
214 /// Parses a named (braced struct) field.
215 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
216 pub fn parse_named(input: ParseStream) -> Result<Self> {
217 let attrs = input.call(Attribute::parse_outer)?;
218 let vis: Visibility = input.parse()?;
219
220 let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]);
221 let ident = if unnamed_field {
222 input.call(Ident::parse_any)
223 } else {
224 input.parse()
225 }?;
226
227 let colon_token: Token![:] = input.parse()?;
228
229 let ty: Type = if unnamed_field
230 && (input.peek(Token![struct])
231 || input.peek(Token![union]) && input.peek2(token::Brace))
232 {
233 let begin = input.fork();
234 input.call(Ident::parse_any)?;
235 input.parse::<FieldsNamed>()?;
236 Type::Verbatim(verbatim::between(&begin, input))
237 } else {
238 input.parse()?
239 };
240
241 Ok(Field {
242 attrs,
243 vis,
244 mutability: FieldMutability::None,
245 ident: Some(ident),
246 colon_token: Some(colon_token),
247 ty,
248 })
249 }
250
251 /// Parses an unnamed (tuple struct) field.
252 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
253 pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
254 Ok(Field {
255 attrs: input.call(Attribute::parse_outer)?,
256 vis: input.parse()?,
257 mutability: FieldMutability::None,
258 ident: None,
259 colon_token: None,
260 ty: input.parse()?,
261 })
262 }
263 }
264}
265
266#[cfg(feature = "printing")]
267mod printing {
268 use super::*;
269 use crate::print::TokensOrDefault;
270 use proc_macro2::TokenStream;
271 use quote::{ToTokens, TokenStreamExt};
272
273 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
274 impl ToTokens for Variant {
275 fn to_tokens(&self, tokens: &mut TokenStream) {
276 tokens.append_all(&self.attrs);
277 self.ident.to_tokens(tokens);
278 self.fields.to_tokens(tokens);
279 if let Some((eq_token, disc)) = &self.discriminant {
280 eq_token.to_tokens(tokens);
281 disc.to_tokens(tokens);
282 }
283 }
284 }
285
286 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
287 impl ToTokens for FieldsNamed {
288 fn to_tokens(&self, tokens: &mut TokenStream) {
289 self.brace_token.surround(tokens, |tokens| {
290 self.named.to_tokens(tokens);
291 });
292 }
293 }
294
295 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
296 impl ToTokens for FieldsUnnamed {
297 fn to_tokens(&self, tokens: &mut TokenStream) {
298 self.paren_token.surround(tokens, |tokens| {
299 self.unnamed.to_tokens(tokens);
300 });
301 }
302 }
303
304 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
305 impl ToTokens for Field {
306 fn to_tokens(&self, tokens: &mut TokenStream) {
307 tokens.append_all(&self.attrs);
308 self.vis.to_tokens(tokens);
309 if let Some(ident) = &self.ident {
310 ident.to_tokens(tokens);
311 TokensOrDefault(&self.colon_token).to_tokens(tokens);
312 }
313 self.ty.to_tokens(tokens);
314 }
315 }
316}
317