1
- use syn :: { parse :: Parse , punctuated :: Punctuated } ;
1
+ use crate :: attr ;
2
2
3
- use crate :: { attr, macro_name} ;
3
+ mod exclude;
4
+ mod for_enum;
5
+ mod for_variant;
4
6
5
- static RECOGNIZED_ENUM_LEVEL_MACROS : & [ & str ] = & [
6
- macro_name:: FROM ,
7
- macro_name:: TRY_INTO ,
8
- macro_name:: FROM_VARIANT ,
9
- macro_name:: INTO_VARIANT ,
10
- macro_name:: AS_VARIANT ,
11
- macro_name:: AS_VARIANT_REF ,
12
- macro_name:: AS_VARIANT_MUT ,
13
- macro_name:: VARIANT_DISCRIMINANT ,
14
- macro_name:: VARIANT_DOWNCAST ,
15
- ] ;
16
-
17
- static RECOGNIZED_VARIANT_LEVEL_MACROS : & [ & str ] = & [
18
- macro_name:: FROM ,
19
- macro_name:: TRY_INTO ,
20
- macro_name:: FROM_VARIANT ,
21
- macro_name:: INTO_VARIANT ,
22
- macro_name:: AS_VARIANT ,
23
- macro_name:: AS_VARIANT_REF ,
24
- macro_name:: AS_VARIANT_MUT ,
25
- ] ;
26
-
27
- #[ derive( Clone , Eq , PartialEq , Debug ) ]
28
- pub ( crate ) enum VariantFieldConfig {
29
- Name ( String ) ,
30
- Index ( usize ) ,
31
- }
32
-
33
- #[ derive( Clone , Default , PartialEq , Eq , Debug ) ]
34
- pub ( crate ) struct MacroSelectionConfig {
35
- pub idents : Vec < syn:: Ident > ,
36
- }
37
-
38
- impl MacroSelectionConfig {
39
- pub fn is_empty ( & self ) -> bool {
40
- self . idents . is_empty ( )
41
- }
42
-
43
- pub fn contains ( & self , name : & str ) -> bool {
44
- self . idents . iter ( ) . any ( |ident| ident == name)
45
- }
46
-
47
- pub fn extend_idents ( & mut self , iter : impl IntoIterator < Item = syn:: Ident > ) {
48
- self . idents . extend ( iter) ;
49
- }
50
- }
51
-
52
- pub ( crate ) type EnumExcludeConfig = MacroSelectionConfig ;
53
- pub ( crate ) type VariantExcludeConfig = MacroSelectionConfig ;
54
-
55
- #[ derive( Clone , Default ) ]
56
- pub ( crate ) struct EncapsulateEnumConfig {
57
- // #[enumcapsulate(exclude(…))]
58
- pub exclude : Option < EnumExcludeConfig > ,
59
- }
60
-
61
- impl EncapsulateEnumConfig {
62
- pub fn is_included ( & self , name : & str ) -> bool {
63
- !self . is_excluded ( name)
64
- }
65
-
66
- pub fn is_excluded ( & self , name : & str ) -> bool {
67
- self . exclude
68
- . as_ref ( )
69
- . map ( |excluded| excluded. contains ( name) )
70
- . unwrap_or ( false )
71
- }
72
- }
73
-
74
- #[ derive( Clone , Default ) ]
75
- pub ( crate ) struct EnumConfig { }
76
-
77
- #[ derive( Clone , Default ) ]
78
- pub ( crate ) struct VariantConfig {
79
- // #[enumcapsulate(exclude(…))]
80
- pub exclude : Option < VariantExcludeConfig > ,
81
-
82
- // #[enumcapsulate(field(…))]
83
- pub field : Option < VariantFieldConfig > ,
84
- }
85
-
86
- impl VariantConfig {
87
- #[ allow( dead_code) ]
88
- pub fn is_included ( & self , name : & str ) -> bool {
89
- !self . is_excluded ( name)
90
- }
91
-
92
- pub fn is_excluded ( & self , name : & str ) -> bool {
93
- let Some ( excluded) = & self . exclude else {
94
- return false ;
95
- } ;
96
-
97
- if excluded. is_empty ( ) {
98
- true
99
- } else {
100
- excluded. contains ( name)
101
- }
102
- }
103
- }
104
-
105
- pub ( crate ) fn encapsulate_config_for_enum (
106
- enum_item : & syn:: ItemEnum ,
107
- ) -> Result < EncapsulateEnumConfig , syn:: Error > {
108
- let mut config = EncapsulateEnumConfig :: default ( ) ;
109
-
110
- parse_enumcapsulate_attrs ( & enum_item. attrs , |meta| {
111
- if meta. path . is_ident ( attr:: EXCLUDE ) {
112
- // #[enumcapsulate(exclude(…))]
113
-
114
- let mut exclude = config. exclude . take ( ) . unwrap_or_default ( ) ;
115
-
116
- let idents = macro_selection_config_for_enum ( & meta) ?. idents ;
117
-
118
- if idents. is_empty ( ) {
119
- return Err ( meta. error ( "expected list" ) ) ;
120
- }
121
-
122
- exclude. extend_idents ( idents) ;
123
-
124
- config. exclude = Some ( exclude) ;
125
- } else {
126
- return Err ( meta. error ( "unrecognized attribute" ) ) ;
127
- }
128
-
129
- Ok ( ( ) )
130
- } ) ?;
131
-
132
- Ok ( config)
133
- }
134
-
135
- pub ( crate ) fn config_for_enum ( enum_item : & syn:: ItemEnum ) -> Result < EnumConfig , syn:: Error > {
136
- let config = EnumConfig :: default ( ) ;
137
-
138
- parse_enumcapsulate_attrs ( & enum_item. attrs , |meta| {
139
- if meta. path . is_ident ( attr:: EXCLUDE ) {
140
- // #[enumcapsulate(exclude(…))]
141
-
142
- meta. parse_nested_meta ( |_meta| {
143
- // Here we're not interested in any of the existing
144
- // sub-attributes, but we need to parse the list anyway.
145
-
146
- Ok ( ( ) )
147
- } ) ?;
148
- } else {
149
- return Err ( meta. error ( "unrecognized attribute" ) ) ;
150
- }
151
-
152
- Ok ( ( ) )
153
- } ) ?;
154
-
155
- Ok ( config)
156
- }
157
-
158
- pub ( crate ) fn config_for_variant ( variant : & syn:: Variant ) -> Result < VariantConfig , syn:: Error > {
159
- let mut config = VariantConfig :: default ( ) ;
160
-
161
- let fields = match & variant. fields {
162
- syn:: Fields :: Named ( fields) => fields. named . iter ( ) . collect ( ) ,
163
- syn:: Fields :: Unnamed ( fields) => fields. unnamed . iter ( ) . collect ( ) ,
164
- syn:: Fields :: Unit => vec ! [ ] ,
165
- } ;
166
-
167
- parse_enumcapsulate_attrs ( & variant. attrs , |meta| {
168
- if meta. path . is_ident ( attr:: EXCLUDE ) {
169
- // #[enumcapsulate(exclude(…))]
170
-
171
- let mut exclude = config. exclude . take ( ) . unwrap_or_default ( ) ;
172
-
173
- exclude. extend_idents ( macro_selection_config_for_variant ( & meta) ?. idents ) ;
174
-
175
- config. exclude = Some ( exclude) ;
176
- } else if meta. path . is_ident ( attr:: FIELD ) {
177
- // #[enumcapsulate(field(…))]
178
- meta. parse_nested_meta ( |meta| {
179
- if meta. path . is_ident ( attr:: NAME ) {
180
- // #[enumcapsulate(field(name = "…"))]
181
-
182
- if !matches ! ( & variant. fields, syn:: Fields :: Named ( _) ) {
183
- return Err ( meta. error ( "no named fields in variant" ) ) ;
184
- }
185
-
186
- let lit: syn:: LitStr = meta. value ( ) ?. parse ( ) ?;
187
- let name = lit. value ( ) ;
188
-
189
- let field_idents: Vec < _ > = fields
190
- . iter ( )
191
- . filter_map ( |& field| field. ident . as_ref ( ) )
192
- . collect ( ) ;
193
-
194
- if field_idents. is_empty ( ) {
195
- return Err ( meta. error ( "no named fields in variant" ) ) ;
196
- }
197
-
198
- let field_exists = field_idents. into_iter ( ) . any ( |ident| ident == & name) ;
199
-
200
- if !field_exists {
201
- return Err ( meta. error ( "field not found in variant" ) ) ;
202
- }
203
-
204
- config. field = Some ( VariantFieldConfig :: Name ( name) ) ;
205
-
206
- Ok ( ( ) )
207
- } else if meta. path . is_ident ( attr:: INDEX ) {
208
- // #[enumcapsulate(field(index = …))]
209
-
210
- if fields. is_empty ( ) {
211
- return Err ( meta. error ( "no fields in variant" ) ) ;
212
- }
213
-
214
- let lit: syn:: LitInt = meta. value ( ) ?. parse ( ) ?;
215
- let index = lit. base10_parse ( ) ?;
216
-
217
- if fields. len ( ) <= index {
218
- return Err ( meta. error ( "field index out of bounds" ) ) ;
219
- }
220
-
221
- config. field = Some ( VariantFieldConfig :: Index ( index) ) ;
222
-
223
- Ok ( ( ) )
224
- } else {
225
- return Err ( meta. error ( "unrecognized attribute" ) ) ;
226
- }
227
- } ) ?;
228
- } else {
229
- return Err ( meta. error ( "unrecognized attribute" ) ) ;
230
- }
231
-
232
- Ok ( ( ) )
233
- } ) ?;
234
-
235
- Ok ( config)
236
- }
7
+ pub ( crate ) use self :: { exclude:: * , for_enum:: * , for_variant:: * } ;
237
8
238
9
pub ( crate ) fn parse_enumcapsulate_attrs (
239
10
attrs : & [ syn:: Attribute ] ,
@@ -246,79 +17,11 @@ pub(crate) fn parse_enumcapsulate_attrs(
246
17
continue ;
247
18
}
248
19
249
- // #[enumcapsulate(…)]
250
20
attr. parse_nested_meta ( & mut logic) ?;
251
21
}
252
22
253
23
Ok ( ( ) )
254
24
}
255
25
256
- pub ( crate ) fn macro_selection_config_for_enum (
257
- meta : & syn:: meta:: ParseNestedMeta < ' _ > ,
258
- ) -> Result < MacroSelectionConfig , syn:: Error > {
259
- let idents = parse_idents_from_meta_list ( meta) ?;
260
-
261
- let recognized = RECOGNIZED_ENUM_LEVEL_MACROS ;
262
- ensure_only_recognized_ident_names ( & idents, recognized) ?;
263
-
264
- Ok ( MacroSelectionConfig { idents } )
265
- }
266
-
267
- pub ( crate ) fn macro_selection_config_for_variant (
268
- meta : & syn:: meta:: ParseNestedMeta < ' _ > ,
269
- ) -> Result < MacroSelectionConfig , syn:: Error > {
270
- let idents = parse_idents_from_meta_list ( meta) ?;
271
-
272
- let recognized = RECOGNIZED_VARIANT_LEVEL_MACROS ;
273
- ensure_only_recognized_ident_names ( & idents, recognized) ?;
274
-
275
- Ok ( MacroSelectionConfig { idents } )
276
- }
277
-
278
- pub ( crate ) fn ensure_only_recognized_ident_names (
279
- idents : & [ syn:: Ident ] ,
280
- recognized : & [ & str ] ,
281
- ) -> Result < ( ) , syn:: Error > {
282
- let mut error: Option < syn:: Error > = None ;
283
-
284
- let unrecognized = idents
285
- . iter ( )
286
- . filter ( |& ident| !recognized. iter ( ) . any ( |recognized| ident == recognized) ) ;
287
-
288
- for ident in unrecognized {
289
- let ident_err = syn:: Error :: new_spanned ( ident, "unrecognized macro derive" ) ;
290
- if let Some ( error) = error. as_mut ( ) {
291
- error. combine ( ident_err) ;
292
- } else {
293
- error = Some ( ident_err)
294
- }
295
- }
296
-
297
- if let Some ( err) = error {
298
- return Err ( err) ;
299
- }
300
-
301
- Ok ( ( ) )
302
- }
303
-
304
- pub ( crate ) fn parse_idents_from_meta_list (
305
- meta : & syn:: meta:: ParseNestedMeta < ' _ > ,
306
- ) -> Result < Vec < syn:: Ident > , syn:: Error > {
307
- let mut idents = vec ! [ ] ;
308
-
309
- let lookahead = meta. input . lookahead1 ( ) ;
310
- if lookahead. peek ( syn:: token:: Paren ) {
311
- let content;
312
- syn:: parenthesized!( content in meta. input) ;
313
-
314
- let punctuated: Punctuated < syn:: Ident , syn:: Token ![ , ] > =
315
- content. parse_terminated ( syn:: Ident :: parse, syn:: Token ![ , ] ) ?;
316
-
317
- idents. extend ( punctuated) ;
318
- }
319
-
320
- Ok ( idents)
321
- }
322
-
323
26
#[ cfg( test) ]
324
27
mod tests;
0 commit comments