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