syn/
derive.rs

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