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