1 | use super::*; |
2 | use crate::punctuated::Punctuated; |
3 | |
4 | ast_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 | |
25 | ast_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 | |
50 | ast_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 | |
63 | ast_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 | |
75 | impl 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 | |
117 | impl 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 | |
130 | impl<'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 | |
139 | impl<'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 | |
148 | ast_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 | |
173 | ast_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 | |
202 | ast_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 | |
213 | ast_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 | |
224 | ast_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" )] |
240 | pub 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" )] |
417 | mod 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 | |