xref: /third_party/rust/crates/syn/src/data.rs (revision fad3a1d3)
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 as _;
160    #[cfg(not(feature = "full"))]
161    use crate::parse::discouraged::Speculative as _;
162    use crate::parse::{Parse, ParseStream, Result};
163
164    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
165    impl Parse for Variant {
166        fn parse(input: ParseStream) -> Result<Self> {
167            let attrs = input.call(Attribute::parse_outer)?;
168            let _visibility: Visibility = input.parse()?;
169            let ident: Ident = input.parse()?;
170            let fields = if input.peek(token::Brace) {
171                Fields::Named(input.parse()?)
172            } else if input.peek(token::Paren) {
173                Fields::Unnamed(input.parse()?)
174            } else {
175                Fields::Unit
176            };
177            let discriminant = if input.peek(Token![=]) {
178                let eq_token: Token![=] = input.parse()?;
179                #[cfg(feature = "full")]
180                let discriminant: Expr = input.parse()?;
181                #[cfg(not(feature = "full"))]
182                let discriminant = {
183                    let begin = input.fork();
184                    let ahead = input.fork();
185                    let mut discriminant: Result<Expr> = ahead.parse();
186                    if discriminant.is_ok() {
187                        input.advance_to(&ahead);
188                    } else if scan_lenient_discriminant(input).is_ok() {
189                        discriminant = Ok(Expr::Verbatim(verbatim::between(&begin, input)));
190                    }
191                    discriminant?
192                };
193                Some((eq_token, discriminant))
194            } else {
195                None
196            };
197            Ok(Variant {
198                attrs,
199                ident,
200                fields,
201                discriminant,
202            })
203        }
204    }
205
206    #[cfg(not(feature = "full"))]
207    pub(crate) fn scan_lenient_discriminant(input: ParseStream) -> Result<()> {
208        use proc_macro2::Delimiter::{self, Brace, Bracket, Parenthesis};
209
210        let consume = |delimiter: Delimiter| {
211            Result::unwrap(input.step(|cursor| match cursor.group(delimiter) {
212                Some((_inside, _span, rest)) => Ok((true, rest)),
213                None => Ok((false, *cursor)),
214            }))
215        };
216
217        macro_rules! consume {
218            [$token:tt] => {
219                input.parse::<Option<Token![$token]>>().unwrap().is_some()
220            };
221        }
222
223        let mut initial = true;
224        let mut depth = 0usize;
225        loop {
226            if initial {
227                if consume![&] {
228                    input.parse::<Option<Token![mut]>>()?;
229                } else if consume![if] || consume![match] || consume![while] {
230                    depth += 1;
231                } else if input.parse::<Option<Lit>>()?.is_some()
232                    || (consume(Brace) || consume(Bracket) || consume(Parenthesis))
233                    || (consume![async] || consume![const] || consume![loop] || consume![unsafe])
234                        && (consume(Brace) || break)
235                {
236                    initial = false;
237                } else if consume![let] {
238                    while !consume![=] {
239                        if !((consume![|] || consume![ref] || consume![mut] || consume![@])
240                            || (consume![!] || input.parse::<Option<Lit>>()?.is_some())
241                            || (consume![..=] || consume![..] || consume![&] || consume![_])
242                            || (consume(Brace) || consume(Bracket) || consume(Parenthesis)))
243                        {
244                            path::parsing::qpath(input, true)?;
245                        }
246                    }
247                } else if input.parse::<Option<Lifetime>>()?.is_some() && !consume![:] {
248                    break;
249                } else if input.parse::<UnOp>().is_err() {
250                    path::parsing::qpath(input, true)?;
251                    initial = consume![!] || depth == 0 && input.peek(token::Brace);
252                }
253            } else if input.is_empty() || input.peek(Token![,]) {
254                return Ok(());
255            } else if depth > 0 && consume(Brace) {
256                if consume![else] && !consume(Brace) {
257                    initial = consume![if] || break;
258                } else {
259                    depth -= 1;
260                }
261            } else if input.parse::<BinOp>().is_ok() || (consume![..] | consume![=]) {
262                initial = true;
263            } else if consume![.] {
264                if input.parse::<Option<LitFloat>>()?.is_none()
265                    && (input.parse::<Member>()?.is_named() && consume![::])
266                {
267                    AngleBracketedGenericArguments::do_parse(None, input)?;
268                }
269            } else if consume![as] {
270                input.parse::<Type>()?;
271            } else if !(consume(Brace) || consume(Bracket) || consume(Parenthesis)) {
272                break;
273            }
274        }
275
276        Err(input.error("unsupported expression"))
277    }
278
279    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
280    impl Parse for FieldsNamed {
281        fn parse(input: ParseStream) -> Result<Self> {
282            let content;
283            Ok(FieldsNamed {
284                brace_token: braced!(content in input),
285                named: content.parse_terminated(Field::parse_named, Token![,])?,
286            })
287        }
288    }
289
290    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
291    impl Parse for FieldsUnnamed {
292        fn parse(input: ParseStream) -> Result<Self> {
293            let content;
294            Ok(FieldsUnnamed {
295                paren_token: parenthesized!(content in input),
296                unnamed: content.parse_terminated(Field::parse_unnamed, Token![,])?,
297            })
298        }
299    }
300
301    impl Field {
302        /// Parses a named (braced struct) field.
303        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
304        pub fn parse_named(input: ParseStream) -> Result<Self> {
305            let attrs = input.call(Attribute::parse_outer)?;
306            let vis: Visibility = input.parse()?;
307
308            let unnamed_field = cfg!(feature = "full") && input.peek(Token![_]);
309            let ident = if unnamed_field {
310                input.call(Ident::parse_any)
311            } else {
312                input.parse()
313            }?;
314
315            let colon_token: Token![:] = input.parse()?;
316
317            let ty: Type = if unnamed_field
318                && (input.peek(Token![struct])
319                    || input.peek(Token![union]) && input.peek2(token::Brace))
320            {
321                let begin = input.fork();
322                input.call(Ident::parse_any)?;
323                input.parse::<FieldsNamed>()?;
324                Type::Verbatim(verbatim::between(&begin, input))
325            } else {
326                input.parse()?
327            };
328
329            Ok(Field {
330                attrs,
331                vis,
332                mutability: FieldMutability::None,
333                ident: Some(ident),
334                colon_token: Some(colon_token),
335                ty,
336            })
337        }
338
339        /// Parses an unnamed (tuple struct) field.
340        #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
341        pub fn parse_unnamed(input: ParseStream) -> Result<Self> {
342            Ok(Field {
343                attrs: input.call(Attribute::parse_outer)?,
344                vis: input.parse()?,
345                mutability: FieldMutability::None,
346                ident: None,
347                colon_token: None,
348                ty: input.parse()?,
349            })
350        }
351    }
352}
353
354#[cfg(feature = "printing")]
355mod printing {
356    use super::*;
357    use crate::print::TokensOrDefault;
358    use proc_macro2::TokenStream;
359    use quote::{ToTokens, TokenStreamExt};
360
361    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
362    impl ToTokens for Variant {
363        fn to_tokens(&self, tokens: &mut TokenStream) {
364            tokens.append_all(&self.attrs);
365            self.ident.to_tokens(tokens);
366            self.fields.to_tokens(tokens);
367            if let Some((eq_token, disc)) = &self.discriminant {
368                eq_token.to_tokens(tokens);
369                disc.to_tokens(tokens);
370            }
371        }
372    }
373
374    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
375    impl ToTokens for FieldsNamed {
376        fn to_tokens(&self, tokens: &mut TokenStream) {
377            self.brace_token.surround(tokens, |tokens| {
378                self.named.to_tokens(tokens);
379            });
380        }
381    }
382
383    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
384    impl ToTokens for FieldsUnnamed {
385        fn to_tokens(&self, tokens: &mut TokenStream) {
386            self.paren_token.surround(tokens, |tokens| {
387                self.unnamed.to_tokens(tokens);
388            });
389        }
390    }
391
392    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
393    impl ToTokens for Field {
394        fn to_tokens(&self, tokens: &mut TokenStream) {
395            tokens.append_all(&self.attrs);
396            self.vis.to_tokens(tokens);
397            if let Some(ident) = &self.ident {
398                ident.to_tokens(tokens);
399                TokensOrDefault(&self.colon_token).to_tokens(tokens);
400            }
401            self.ty.to_tokens(tokens);
402        }
403    }
404}
405