xref: /third_party/rust/crates/syn/src/derive.rs (revision fad3a1d3)
1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5    /// Data structure sent to a `proc_macro_derive` macro.
6    #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
7    pub struct DeriveInput {
8        pub attrs: Vec<Attribute>,
9        pub vis: Visibility,
10        pub ident: Ident,
11        pub generics: Generics,
12        pub data: Data,
13    }
14}
15
16ast_enum! {
17    /// The storage of a struct, enum or union data structure.
18    ///
19    /// # Syntax tree enum
20    ///
21    /// This type is a [syntax tree enum].
22    ///
23    /// [syntax tree enum]: Expr#syntax-tree-enums
24    #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
25    pub enum Data {
26        Struct(DataStruct),
27        Enum(DataEnum),
28        Union(DataUnion),
29    }
30}
31
32ast_struct! {
33    /// A struct input to a `proc_macro_derive` macro.
34    #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
35    pub struct DataStruct {
36        pub struct_token: Token![struct],
37        pub fields: Fields,
38        pub semi_token: Option<Token![;]>,
39    }
40}
41
42ast_struct! {
43    /// An enum input to a `proc_macro_derive` macro.
44    #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
45    pub struct DataEnum {
46        pub enum_token: Token![enum],
47        pub brace_token: token::Brace,
48        pub variants: Punctuated<Variant, Token![,]>,
49    }
50}
51
52ast_struct! {
53    /// An untagged union input to a `proc_macro_derive` macro.
54    #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
55    pub struct DataUnion {
56        pub union_token: Token![union],
57        pub fields: FieldsNamed,
58    }
59}
60
61#[cfg(feature = "parsing")]
62pub(crate) mod parsing {
63    use super::*;
64    use crate::parse::{Parse, ParseStream, Result};
65
66    #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
67    impl Parse for DeriveInput {
68        fn parse(input: ParseStream) -> Result<Self> {
69            let attrs = input.call(Attribute::parse_outer)?;
70            let vis = input.parse::<Visibility>()?;
71
72            let lookahead = input.lookahead1();
73            if lookahead.peek(Token![struct]) {
74                let struct_token = input.parse::<Token![struct]>()?;
75                let ident = input.parse::<Ident>()?;
76                let generics = input.parse::<Generics>()?;
77                let (where_clause, fields, semi) = data_struct(input)?;
78                Ok(DeriveInput {
79                    attrs,
80                    vis,
81                    ident,
82                    generics: Generics {
83                        where_clause,
84                        ..generics
85                    },
86                    data: Data::Struct(DataStruct {
87                        struct_token,
88                        fields,
89                        semi_token: semi,
90                    }),
91                })
92            } else if lookahead.peek(Token![enum]) {
93                let enum_token = input.parse::<Token![enum]>()?;
94                let ident = input.parse::<Ident>()?;
95                let generics = input.parse::<Generics>()?;
96                let (where_clause, brace, variants) = data_enum(input)?;
97                Ok(DeriveInput {
98                    attrs,
99                    vis,
100                    ident,
101                    generics: Generics {
102                        where_clause,
103                        ..generics
104                    },
105                    data: Data::Enum(DataEnum {
106                        enum_token,
107                        brace_token: brace,
108                        variants,
109                    }),
110                })
111            } else if lookahead.peek(Token![union]) {
112                let union_token = input.parse::<Token![union]>()?;
113                let ident = input.parse::<Ident>()?;
114                let generics = input.parse::<Generics>()?;
115                let (where_clause, fields) = data_union(input)?;
116                Ok(DeriveInput {
117                    attrs,
118                    vis,
119                    ident,
120                    generics: Generics {
121                        where_clause,
122                        ..generics
123                    },
124                    data: Data::Union(DataUnion {
125                        union_token,
126                        fields,
127                    }),
128                })
129            } else {
130                Err(lookahead.error())
131            }
132        }
133    }
134
135    pub(crate) fn data_struct(
136        input: ParseStream,
137    ) -> Result<(Option<WhereClause>, Fields, Option<Token![;]>)> {
138        let mut lookahead = input.lookahead1();
139        let mut where_clause = None;
140        if lookahead.peek(Token![where]) {
141            where_clause = Some(input.parse()?);
142            lookahead = input.lookahead1();
143        }
144
145        if where_clause.is_none() && lookahead.peek(token::Paren) {
146            let fields = input.parse()?;
147
148            lookahead = input.lookahead1();
149            if lookahead.peek(Token![where]) {
150                where_clause = Some(input.parse()?);
151                lookahead = input.lookahead1();
152            }
153
154            if lookahead.peek(Token![;]) {
155                let semi = input.parse()?;
156                Ok((where_clause, Fields::Unnamed(fields), Some(semi)))
157            } else {
158                Err(lookahead.error())
159            }
160        } else if lookahead.peek(token::Brace) {
161            let fields = input.parse()?;
162            Ok((where_clause, Fields::Named(fields), None))
163        } else if lookahead.peek(Token![;]) {
164            let semi = input.parse()?;
165            Ok((where_clause, Fields::Unit, Some(semi)))
166        } else {
167            Err(lookahead.error())
168        }
169    }
170
171    pub(crate) fn data_enum(
172        input: ParseStream,
173    ) -> Result<(
174        Option<WhereClause>,
175        token::Brace,
176        Punctuated<Variant, Token![,]>,
177    )> {
178        let where_clause = input.parse()?;
179
180        let content;
181        let brace = braced!(content in input);
182        let variants = content.parse_terminated(Variant::parse, Token![,])?;
183
184        Ok((where_clause, brace, variants))
185    }
186
187    pub(crate) fn data_union(input: ParseStream) -> Result<(Option<WhereClause>, FieldsNamed)> {
188        let where_clause = input.parse()?;
189        let fields = input.parse()?;
190        Ok((where_clause, fields))
191    }
192}
193
194#[cfg(feature = "printing")]
195mod printing {
196    use super::*;
197    use crate::attr::FilterAttrs;
198    use crate::print::TokensOrDefault;
199    use proc_macro2::TokenStream;
200    use quote::ToTokens;
201
202    #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
203    impl ToTokens for DeriveInput {
204        fn to_tokens(&self, tokens: &mut TokenStream) {
205            for attr in self.attrs.outer() {
206                attr.to_tokens(tokens);
207            }
208            self.vis.to_tokens(tokens);
209            match &self.data {
210                Data::Struct(d) => d.struct_token.to_tokens(tokens),
211                Data::Enum(d) => d.enum_token.to_tokens(tokens),
212                Data::Union(d) => d.union_token.to_tokens(tokens),
213            }
214            self.ident.to_tokens(tokens);
215            self.generics.to_tokens(tokens);
216            match &self.data {
217                Data::Struct(data) => match &data.fields {
218                    Fields::Named(fields) => {
219                        self.generics.where_clause.to_tokens(tokens);
220                        fields.to_tokens(tokens);
221                    }
222                    Fields::Unnamed(fields) => {
223                        fields.to_tokens(tokens);
224                        self.generics.where_clause.to_tokens(tokens);
225                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
226                    }
227                    Fields::Unit => {
228                        self.generics.where_clause.to_tokens(tokens);
229                        TokensOrDefault(&data.semi_token).to_tokens(tokens);
230                    }
231                },
232                Data::Enum(data) => {
233                    self.generics.where_clause.to_tokens(tokens);
234                    data.brace_token.surround(tokens, |tokens| {
235                        data.variants.to_tokens(tokens);
236                    });
237                }
238                Data::Union(data) => {
239                    self.generics.where_clause.to_tokens(tokens);
240                    data.fields.to_tokens(tokens);
241                }
242            }
243        }
244    }
245}
246