1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5 /// An enum variant.
6 ///
7 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
8 /// feature.*
9 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
10 pub struct Variant {
11 /// Attributes tagged on the variant.
12 pub attrs: Vec<Attribute>,
13
14 /// Name of the variant.
15 pub ident: Ident,
16
17 /// Content stored in the variant.
18 pub fields: Fields,
19
20 /// Explicit discriminant: `Variant = 1`
21 pub discriminant: Option<(Token![=], Expr)>,
22 }
23}
24
25ast_enum_of_structs! {
26 /// Data stored within an enum variant or struct.
27 ///
28 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
29 /// feature.*
30 ///
31 /// # Syntax tree enum
32 ///
33 /// This type is a [syntax tree enum].
34 ///
35 /// [syntax tree enum]: Expr#syntax-tree-enums
36 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
37 pub enum Fields {
38 /// Named fields of a struct or struct variant such as `Point { x: f64,
39 /// y: f64 }`.
40 Named(FieldsNamed),
41
42 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
43 Unnamed(FieldsUnnamed),
44
45 /// Unit struct or unit variant such as `None`.
46 Unit,
47 }
48}
49
50ast_struct! {
51 /// Named fields of a struct or struct variant such as `Point { x: f64,
52 /// y: f64 }`.
53 ///
54 /// *This type is available only if Syn is built with the `"derive"` or
55 /// `"full"` feature.*
56 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
57 pub struct FieldsNamed {
58 pub brace_token: token::Brace,
59 pub named: Punctuated<Field, Token![,]>,
60 }
61}
62
63ast_struct! {
64 /// Unnamed fields of a tuple struct or tuple variant such as `Some(T)`.
65 ///
66 /// *This type is available only if Syn is built with the `"derive"` or
67 /// `"full"` feature.*
68 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
69 pub struct FieldsUnnamed {
70 pub paren_token: token::Paren,
71 pub unnamed: Punctuated<Field, Token![,]>,
72 }
73}
74
75impl Fields {
76 /// Get an iterator over the borrowed [`Field`] items in this object. This
77 /// iterator can be used to iterate over a named or unnamed struct or
78 /// variant's fields uniformly.
79 pub fn iter(&self) -> punctuated::Iter<Field> {
80 match self {
81 Fields::Unit => crate::punctuated::empty_punctuated_iter(),
82 Fields::Named(f) => f.named.iter(),
83 Fields::Unnamed(f) => f.unnamed.iter(),
84 }
85 }
86
87 /// Get an iterator over the mutably borrowed [`Field`] items in this
88 /// object. This iterator can be used to iterate over a named or unnamed
89 /// struct or variant's fields uniformly.
90 pub fn iter_mut(&mut self) -> punctuated::IterMut<Field> {
91 match self {
92 Fields::Unit => crate::punctuated::empty_punctuated_iter_mut(),
93 Fields::Named(f) => f.named.iter_mut(),
94 Fields::Unnamed(f) => f.unnamed.iter_mut(),
95 }
96 }
97
98 /// Returns the number of fields.
99 pub fn len(&self) -> usize {
100 match self {
101 Fields::Unit => 0,
102 Fields::Named(f) => f.named.len(),
103 Fields::Unnamed(f) => f.unnamed.len(),
104 }
105 }
106
107 /// Returns `true` if there are zero fields.
108 pub fn is_empty(&self) -> bool {
109 match self {
110 Fields::Unit => true,
111 Fields::Named(f) => f.named.is_empty(),
112 Fields::Unnamed(f) => f.unnamed.is_empty(),
113 }
114 }
115}
116
117impl IntoIterator for Fields {
118 type Item = Field;
119 type IntoIter = punctuated::IntoIter<Field>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 match self {
123 Fields::Unit => Punctuated::<Field, ()>::new().into_iter(),
124 Fields::Named(f: FieldsNamed) => f.named.into_iter(),
125 Fields::Unnamed(f: FieldsUnnamed) => f.unnamed.into_iter(),
126 }
127 }
128}
129
130impl<'a> IntoIterator for &'a Fields {
131 type Item = &'a Field;
132 type IntoIter = punctuated::Iter<'a, Field>;
133
134 fn into_iter(self) -> Self::IntoIter {
135 self.iter()
136 }
137}
138
139impl<'a> IntoIterator for &'a mut Fields {
140 type Item = &'a mut Field;
141 type IntoIter = punctuated::IterMut<'a, Field>;
142
143 fn into_iter(self) -> Self::IntoIter {
144 self.iter_mut()
145 }
146}
147
148ast_struct! {
149 /// A field of a struct or enum variant.
150 ///
151 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
152 /// feature.*
153 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
154 pub struct Field {
155 /// Attributes tagged on the field.
156 pub attrs: Vec<Attribute>,
157
158 /// Visibility of the field.
159 pub vis: Visibility,
160
161 /// Name of the field, if any.
162 ///
163 /// Fields of tuple structs have no names.
164 pub ident: Option<Ident>,
165
166 pub colon_token: Option<Token![:]>,
167
168 /// Type of the field.
169 pub ty: Type,
170 }
171}
172
173ast_enum_of_structs! {
174 /// The visibility level of an item: inherited or `pub` or
175 /// `pub(restricted)`.
176 ///
177 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
178 /// feature.*
179 ///
180 /// # Syntax tree enum
181 ///
182 /// This type is a [syntax tree enum].
183 ///
184 /// [syntax tree enum]: Expr#syntax-tree-enums
185 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
186 pub enum Visibility {
187 /// A public visibility level: `pub`.
188 Public(VisPublic),
189
190 /// A crate-level visibility: `crate`.
191 Crate(VisCrate),
192
193 /// A visibility level restricted to some path: `pub(self)` or
194 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
195 Restricted(VisRestricted),
196
197 /// An inherited visibility, which usually means private.
198 Inherited,
199 }
200}
201
202ast_struct! {
203 /// A public visibility level: `pub`.
204 ///
205 /// *This type is available only if Syn is built with the `"derive"` or
206 /// `"full"` feature.*
207 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
208 pub struct VisPublic {
209 pub pub_token: Token![pub],
210 }
211}
212
213ast_struct! {
214 /// A crate-level visibility: `crate`.
215 ///
216 /// *This type is available only if Syn is built with the `"derive"` or
217 /// `"full"` feature.*
218 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
219 pub struct VisCrate {
220 pub crate_token: Token![crate],
221 }
222}
223
224ast_struct! {
225 /// A visibility level restricted to some path: `pub(self)` or
226 /// `pub(super)` or `pub(crate)` or `pub(in some::module)`.
227 ///
228 /// *This type is available only if Syn is built with the `"derive"` or
229 /// `"full"` feature.*
230 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
231 pub struct VisRestricted {
232 pub pub_token: Token![pub],
233 pub paren_token: token::Paren,
234 pub in_token: Option<Token![in]>,
235 pub path: Box<Path>,
236 }
237}
238
239#[cfg(feature = "parsing")]
240pub mod parsing {
241 use super::*;
242 use crate::ext::IdentExt;
243 use crate::parse::discouraged::Speculative;
244 use crate::parse::{Parse, ParseStream, Result};
245
246 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
247 impl Parse for Variant {
248 fn parse(input: ParseStream) -> Result<Self> {
249 let attrs = input.call(Attribute::parse_outer)?;
250 let _visibility: Visibility = input.parse()?;
251 let ident: Ident = input.parse()?;
252 let fields = if input.peek(token::Brace) {
253 Fields::Named(input.parse()?)
254 } else if input.peek(token::Paren) {
255 Fields::Unnamed(input.parse()?)
256 } else {
257 Fields::Unit
258 };
259 let discriminant = if input.peek(Token![=]) {
260 let eq_token: Token![=] = input.parse()?;
261 let discriminant: Expr = input.parse()?;
262 Some((eq_token, discriminant))
263 } else {
264 None
265 };
266 Ok(Variant {
267 attrs,
268 ident,
269 fields,
270 discriminant,
271 })
272 }
273 }
274
275 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
276 impl Parse for FieldsNamed {
277 fn parse(input: ParseStream) -> Result<Self> {
278 let content;
279 Ok(FieldsNamed {
280 brace_token: braced!(content in input),
281 named: content.parse_terminated(Field::parse_named)?,
282 })
283 }
284 }
285
286 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
287 impl Parse for FieldsUnnamed {
288 fn parse(input: ParseStream) -> Result<Self> {
289 let content;
290 Ok(FieldsUnnamed {
291 paren_token: parenthesized!(content in input),
292 unnamed: content.parse_terminated(Field::parse_unnamed)?,
293 })
294 }
295 }
296
297 impl Field {
298 /// Parses a named (braced struct) field.
299 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
300 pub fn parse_named(input: ParseStream) -> Result<Self> {
301 Ok(Field {
302 attrs: input.call(Attribute::parse_outer)?,
303 vis: input.parse()?,
304 ident: Some(if input.peek(Token![_]) {
305 input.call(Ident::parse_any)
306 } else {
307 input.parse()
308 }?),
309 colon_token: Some(input.parse()?),
310 ty: input.parse()?,
311 })
312 }
313
314 /// Parses an unnamed (tuple struct) field.
315 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
316 pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
317 Ok(Field {
318 attrs: input.call(Attribute::parse_outer)?,
319 vis: input.parse()?,
320 ident: None,
321 colon_token: None,
322 ty: input.parse()?,
323 })
324 }
325 }
326
327 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
328 impl Parse for Visibility {
329 fn parse(input: ParseStream) -> Result<Self> {
330 // Recognize an empty None-delimited group, as produced by a $:vis
331 // matcher that matched no tokens.
332 if input.peek(token::Group) {
333 let ahead = input.fork();
334 let group = crate::group::parse_group(&ahead)?;
335 if group.content.is_empty() {
336 input.advance_to(&ahead);
337 return Ok(Visibility::Inherited);
338 }
339 }
340
341 if input.peek(Token![pub]) {
342 Self::parse_pub(input)
343 } else if input.peek(Token![crate]) {
344 Self::parse_crate(input)
345 } else {
346 Ok(Visibility::Inherited)
347 }
348 }
349 }
350
351 impl Visibility {
352 fn parse_pub(input: ParseStream) -> Result<Self> {
353 let pub_token = input.parse::<Token![pub]>()?;
354
355 if input.peek(token::Paren) {
356 let ahead = input.fork();
357
358 let content;
359 let paren_token = parenthesized!(content in ahead);
360 if content.peek(Token![crate])
361 || content.peek(Token![self])
362 || content.peek(Token![super])
363 {
364 let path = content.call(Ident::parse_any)?;
365
366 // Ensure there are no additional tokens within `content`.
367 // Without explicitly checking, we may misinterpret a tuple
368 // field as a restricted visibility, causing a parse error.
369 // e.g. `pub (crate::A, crate::B)` (Issue #720).
370 if content.is_empty() {
371 input.advance_to(&ahead);
372 return Ok(Visibility::Restricted(VisRestricted {
373 pub_token,
374 paren_token,
375 in_token: None,
376 path: Box::new(Path::from(path)),
377 }));
378 }
379 } else if content.peek(Token![in]) {
380 let in_token: Token![in] = content.parse()?;
381 let path = content.call(Path::parse_mod_style)?;
382
383 input.advance_to(&ahead);
384 return Ok(Visibility::Restricted(VisRestricted {
385 pub_token,
386 paren_token,
387 in_token: Some(in_token),
388 path: Box::new(path),
389 }));
390 }
391 }
392
393 Ok(Visibility::Public(VisPublic { pub_token }))
394 }
395
396 fn parse_crate(input: ParseStream) -> Result<Self> {
397 if input.peek2(Token![::]) {
398 Ok(Visibility::Inherited)
399 } else {
400 Ok(Visibility::Crate(VisCrate {
401 crate_token: input.parse()?,
402 }))
403 }
404 }
405
406 #[cfg(feature = "full")]
407 pub(crate) fn is_some(&self) -> bool {
408 match self {
409 Visibility::Inherited => false,
410 _ => true,
411 }
412 }
413 }
414}
415
416#[cfg(feature = "printing")]
417mod printing {
418 use super::*;
419 use crate::print::TokensOrDefault;
420 use proc_macro2::TokenStream;
421 use quote::{ToTokens, TokenStreamExt};
422
423 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
424 impl ToTokens for Variant {
425 fn to_tokens(&self, tokens: &mut TokenStream) {
426 tokens.append_all(&self.attrs);
427 self.ident.to_tokens(tokens);
428 self.fields.to_tokens(tokens);
429 if let Some((eq_token, disc)) = &self.discriminant {
430 eq_token.to_tokens(tokens);
431 disc.to_tokens(tokens);
432 }
433 }
434 }
435
436 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
437 impl ToTokens for FieldsNamed {
438 fn to_tokens(&self, tokens: &mut TokenStream) {
439 self.brace_token.surround(tokens, |tokens| {
440 self.named.to_tokens(tokens);
441 });
442 }
443 }
444
445 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
446 impl ToTokens for FieldsUnnamed {
447 fn to_tokens(&self, tokens: &mut TokenStream) {
448 self.paren_token.surround(tokens, |tokens| {
449 self.unnamed.to_tokens(tokens);
450 });
451 }
452 }
453
454 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
455 impl ToTokens for Field {
456 fn to_tokens(&self, tokens: &mut TokenStream) {
457 tokens.append_all(&self.attrs);
458 self.vis.to_tokens(tokens);
459 if let Some(ident) = &self.ident {
460 ident.to_tokens(tokens);
461 TokensOrDefault(&self.colon_token).to_tokens(tokens);
462 }
463 self.ty.to_tokens(tokens);
464 }
465 }
466
467 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
468 impl ToTokens for VisPublic {
469 fn to_tokens(&self, tokens: &mut TokenStream) {
470 self.pub_token.to_tokens(tokens);
471 }
472 }
473
474 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
475 impl ToTokens for VisCrate {
476 fn to_tokens(&self, tokens: &mut TokenStream) {
477 self.crate_token.to_tokens(tokens);
478 }
479 }
480
481 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
482 impl ToTokens for VisRestricted {
483 fn to_tokens(&self, tokens: &mut TokenStream) {
484 self.pub_token.to_tokens(tokens);
485 self.paren_token.surround(tokens, |tokens| {
486 // TODO: If we have a path which is not "self" or "super" or
487 // "crate", automatically add the "in" token.
488 self.in_token.to_tokens(tokens);
489 self.path.to_tokens(tokens);
490 });
491 }
492 }
493}
494