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