syn/
derive.rs

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