@@ -2,73 +2,19 @@ extern crate proc_macro;
2
2
3
3
use quote:: { quote, quote_spanned} ;
4
4
use syn:: {
5
- parse_macro_input, parenthesized, parse_quote, DeriveInput , Data ,
6
- Error , Generics , GenericParam , TypeParamBound , Fields , Member ,
7
- Index , Type , GenericArgument , Attribute , PathArguments , Meta ,
8
- TypeParam , WherePredicate , PredicateType , Token , Lifetime
5
+ parse_macro_input, parenthesized, parse_quote, DeriveInput ,
6
+ Data , Error , Generics , GenericParam , TypeParamBound , Fields ,
7
+ Member , Index , Type , GenericArgument , Attribute , PathArguments ,
8
+ Meta , TypeParam , WherePredicate , PredicateType , Token , Lifetime ,
9
+ NestedMeta , Lit
9
10
} ;
10
11
use proc_macro2:: { Ident , TokenStream , Span } ;
11
12
use syn:: spanned:: Spanned ;
12
- use syn:: parse:: { ParseStream , Parse , ParseBuffer } ;
13
+ use syn:: parse:: { ParseStream , Parse } ;
13
14
use std:: collections:: HashSet ;
14
15
use syn:: export:: fmt:: Display ;
15
16
use std:: io:: Write ;
16
17
17
- use indexmap:: IndexMap ;
18
-
19
- struct AttributeOptions {
20
- ignored : bool
21
- }
22
- impl Default for AttributeOptions {
23
- fn default ( ) -> AttributeOptions {
24
- AttributeOptions {
25
- ignored : false
26
- }
27
- }
28
- }
29
- impl AttributeOptions {
30
- pub fn find ( attrs : & [ Attribute ] ) -> Result < Self , Error > {
31
- attrs. iter ( ) . find_map ( |attr| {
32
- if attr. path . is_ident ( "zerogc" ) {
33
- Some ( syn:: parse2 :: < AttributeOptions > ( attr. tokens . clone ( ) ) )
34
- } else {
35
- None
36
- }
37
- } ) . unwrap_or_else ( || Ok ( AttributeOptions :: default ( ) ) )
38
- }
39
- }
40
- impl Parse for AttributeOptions {
41
- fn parse ( raw_input : & ParseBuffer ) -> Result < Self , Error > {
42
- let input;
43
- parenthesized ! ( input in raw_input) ;
44
- let mut result = AttributeOptions :: default ( ) ;
45
- while !input. is_empty ( ) {
46
- let meta = input. parse :: < Meta > ( ) ?;
47
- if meta. path ( ) . is_ident ( "ignore" ) {
48
- if !matches ! ( meta, Meta :: Path ( _) ) {
49
- return Err ( Error :: new (
50
- meta. span ( ) ,
51
- "Malformed attribute for #[zerogc(ignore)]"
52
- ) )
53
- }
54
- if result. ignored {
55
- return Err ( Error :: new (
56
- meta. span ( ) ,
57
- "Already ignoring attribute"
58
- ) )
59
- }
60
- result. ignored = true ;
61
- } else {
62
- return Err ( Error :: new (
63
- meta. span ( ) ,
64
- "Unknown attribute flag"
65
- ) ) ;
66
- }
67
- }
68
- Ok ( result)
69
- }
70
- }
71
-
72
18
struct MutableFieldOpts {
73
19
public : bool
74
20
}
@@ -155,50 +101,28 @@ impl Parse for GcFieldAttrs {
155
101
}
156
102
157
103
struct GcTypeInfo {
158
- config : TypeConfig ,
159
- params : IndexMap < Ident , AttributeOptions > ,
160
- lifetimes : IndexMap < Lifetime , AttributeOptions > ,
104
+ config : TypeAttrs ,
161
105
}
162
106
impl GcTypeInfo {
163
- fn ignored_params ( & self ) -> HashSet < Ident > {
164
- self . params . iter ( )
165
- . filter ( |& ( _, ref opts) | opts. ignored )
166
- . map ( |( name, _) | name. clone ( ) )
167
- . collect ( )
168
- }
169
107
fn parse ( input : & DeriveInput ) -> Result < GcTypeInfo , Error > {
170
- let config = TypeConfig :: find ( & * input. attrs ) ?;
171
- let mut params = IndexMap :: new ( ) ;
172
- let mut lifetimes = IndexMap :: new ( ) ;
173
- for lt in input. generics . lifetimes ( ) {
174
- lifetimes. insert (
175
- lt. lifetime . clone ( ) ,
176
- AttributeOptions :: find ( & lt. attrs ) ?
177
- ) ;
178
- }
179
- for param in input. generics . type_params ( ) {
180
- params. insert (
181
- param. ident . clone ( ) ,
182
- AttributeOptions :: find ( & param. attrs ) ?
183
- ) ;
184
- }
185
- if let Some ( attrs) = lifetimes. get ( & config. gc_lifetime ( ) ) {
186
- if attrs. ignored {
187
- return Err ( Error :: new (
188
- config. gc_lifetime ( ) . span ( ) ,
189
- "Ignored gc lifetime"
190
- ) )
191
- }
108
+ let config = TypeAttrs :: find ( & * input. attrs ) ?;
109
+ if config. ignored_lifetimes . contains ( & config. gc_lifetime ( ) ) {
110
+ return Err ( Error :: new (
111
+ config. gc_lifetime ( ) . span ( ) ,
112
+ "Ignored gc lifetime"
113
+ ) )
192
114
}
193
- Ok ( GcTypeInfo { config, params , lifetimes } )
115
+ Ok ( GcTypeInfo { config } )
194
116
}
195
117
}
196
- struct TypeConfig {
118
+ struct TypeAttrs {
197
119
is_copy : bool ,
198
120
nop_trace : bool ,
199
- gc_lifetime : Option < Lifetime >
121
+ gc_lifetime : Option < Lifetime > ,
122
+ ignore_params : HashSet < Ident > ,
123
+ ignored_lifetimes : HashSet < Lifetime >
200
124
}
201
- impl TypeConfig {
125
+ impl TypeAttrs {
202
126
fn gc_lifetime ( & self ) -> Lifetime {
203
127
match self . gc_lifetime {
204
128
Some ( ref lt) => lt. clone ( ) ,
@@ -208,27 +132,29 @@ impl TypeConfig {
208
132
pub fn find ( attrs : & [ Attribute ] ) -> Result < Self , Error > {
209
133
attrs. iter ( ) . find_map ( |attr| {
210
134
if attr. path . is_ident ( "zerogc" ) {
211
- Some ( syn:: parse2 :: < TypeConfig > ( attr. tokens . clone ( ) ) )
135
+ Some ( syn:: parse2 :: < TypeAttrs > ( attr. tokens . clone ( ) ) )
212
136
} else {
213
137
None
214
138
}
215
- } ) . unwrap_or_else ( || Ok ( TypeConfig :: default ( ) ) )
139
+ } ) . unwrap_or_else ( || Ok ( TypeAttrs :: default ( ) ) )
216
140
}
217
141
}
218
- impl Default for TypeConfig {
142
+ impl Default for TypeAttrs {
219
143
fn default ( ) -> Self {
220
- TypeConfig {
144
+ TypeAttrs {
221
145
is_copy : false ,
222
146
nop_trace : false ,
223
- gc_lifetime : None
147
+ gc_lifetime : None ,
148
+ ignore_params : Default :: default ( ) ,
149
+ ignored_lifetimes : Default :: default ( ) ,
224
150
}
225
151
}
226
152
}
227
- impl Parse for TypeConfig {
153
+ impl Parse for TypeAttrs {
228
154
fn parse ( raw_input : ParseStream ) -> Result < Self , Error > {
229
155
let input;
230
156
parenthesized ! ( input in raw_input) ;
231
- let mut result = TypeConfig :: default ( ) ;
157
+ let mut result = TypeAttrs :: default ( ) ;
232
158
while !input. is_empty ( ) {
233
159
let meta = input. parse :: < Meta > ( ) ?;
234
160
if meta. path ( ) . is_ident ( "copy" ) {
@@ -268,7 +194,7 @@ impl Parse for TypeConfig {
268
194
}
269
195
let s = match meta {
270
196
Meta :: NameValue ( syn:: MetaNameValue {
271
- lit : :: syn :: Lit :: Str ( ref s) , ..
197
+ lit : Lit :: Str ( ref s) , ..
272
198
} ) => s,
273
199
_ => {
274
200
return Err ( Error :: new (
@@ -287,6 +213,89 @@ impl Parse for TypeConfig {
287
213
}
288
214
} ;
289
215
result. gc_lifetime = Some ( lifetime) ;
216
+ } else if meta. path ( ) . is_ident ( "ignore_params" ) {
217
+ if !result. ignore_params . is_empty ( ) {
218
+ return Err ( Error :: new (
219
+ meta. span ( ) ,
220
+ "Duplicate flags: #[zerogc(ignore_params)]"
221
+ ) )
222
+ }
223
+ let list = match meta {
224
+ Meta :: List ( ref list) if list. nested . is_empty ( ) => {
225
+ return Err ( Error :: new (
226
+ list. span ( ) ,
227
+ "Empty list for #[zerogc(ignore_params)]"
228
+ ) )
229
+ }
230
+ Meta :: List ( list) => list,
231
+ _ => return Err ( Error :: new (
232
+ meta. span ( ) ,
233
+ "Expected a list attribute for #[zerogc(ignore_params)]"
234
+ ) )
235
+ } ;
236
+ for nested in list. nested {
237
+ match nested {
238
+ NestedMeta :: Meta ( Meta :: Path ( ref p) )
239
+ if p. get_ident ( ) . is_some ( ) => {
240
+ let ident = p. get_ident ( ) . unwrap ( ) ;
241
+ if !result. ignore_params . insert ( ident. clone ( ) ) {
242
+ return Err ( Error :: new (
243
+ ident. span ( ) ,
244
+ "Duplicate parameter to ignore"
245
+ ) ) ;
246
+ }
247
+ }
248
+ _ => return Err ( Error :: new (
249
+ nested. span ( ) ,
250
+ "Invalid list value for #[zerogc(ignore_param)]"
251
+ ) )
252
+ }
253
+ }
254
+ } else if meta. path ( ) . is_ident ( "ignore_lifetimes" ) {
255
+ if !result. ignore_params . is_empty ( ) {
256
+ return Err ( Error :: new (
257
+ meta. span ( ) ,
258
+ "Duplicate flags: #[zerogc(ignore_lifetimes)]"
259
+ ) )
260
+ }
261
+ let list = match meta {
262
+ Meta :: List ( ref list) if list. nested . is_empty ( ) => {
263
+ return Err ( Error :: new (
264
+ list. span ( ) ,
265
+ "Empty list for #[zerogc(ignore_lifetimes)]"
266
+ ) )
267
+ }
268
+ Meta :: List ( list) => list,
269
+ _ => return Err ( Error :: new (
270
+ meta. span ( ) ,
271
+ "Expected a list attribute for #[zerogc(ignore_lifetimes)]"
272
+ ) )
273
+ } ;
274
+ for nested in list. nested {
275
+ let lifetime = match nested {
276
+ NestedMeta :: Lit ( Lit :: Str ( ref s) ) => {
277
+ s. parse :: < Lifetime > ( ) ?
278
+ } ,
279
+ NestedMeta :: Meta ( Meta :: Path ( ref p) ) if p. get_ident ( ) . is_some ( ) => {
280
+ let ident = p. get_ident ( ) . unwrap ( ) ;
281
+ Lifetime {
282
+ ident : ident. clone ( ) ,
283
+ // Fake the appostrophie's span as matching the ident
284
+ apostrophe : ident. span ( )
285
+ }
286
+ } ,
287
+ _ => return Err ( Error :: new (
288
+ nested. span ( ) ,
289
+ "Invalid list value for #[zerogc(ignore_lifetimes)]"
290
+ ) )
291
+ } ;
292
+ if !result. ignored_lifetimes . insert ( lifetime. clone ( ) ) {
293
+ return Err ( Error :: new (
294
+ lifetime. span ( ) ,
295
+ "Duplicate lifetime to ignore"
296
+ ) ) ;
297
+ }
298
+ }
290
299
} else {
291
300
return Err ( Error :: new (
292
301
meta. span ( ) , "Unknown type flag"
@@ -300,7 +309,7 @@ impl Parse for TypeConfig {
300
309
}
301
310
}
302
311
303
- #[ proc_macro_derive( Trace ) ]
312
+ #[ proc_macro_derive( Trace , attributes ( zerogc ) ) ]
304
313
pub fn derive_trace ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
305
314
let input = parse_macro_input ! ( input as DeriveInput ) ;
306
315
let res = From :: from ( impl_derive_trace ( & input)
@@ -479,8 +488,8 @@ fn impl_brand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
479
488
GenericParam :: Lifetime ( ref l) => {
480
489
if l. lifetime == info. config . gc_lifetime ( ) {
481
490
rewritten_param = parse_quote ! ( ' new_gc) ;
482
- assert ! ( !info. lifetimes [ & l. lifetime] . ignored ) ;
483
- } else if info. lifetimes [ & l. lifetime ] . ignored {
491
+ assert ! ( !info. config . ignored_lifetimes . contains ( & l. lifetime) ) ;
492
+ } else if info. config . ignored_lifetimes . contains ( & l. lifetime ) {
484
493
rewritten_param = GenericArgument :: Lifetime ( l. lifetime . clone ( ) ) ;
485
494
} else {
486
495
return Err ( Error :: new (
@@ -509,11 +518,11 @@ fn impl_brand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
509
518
}
510
519
} )
511
520
}
512
- fn impl_trace ( target : & DeriveInput , attrs : & GcTypeInfo ) -> Result < TokenStream , Error > {
521
+ fn impl_trace ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
513
522
let name = & target. ident ;
514
523
let generics = add_trait_bounds_except (
515
524
& target. generics , parse_quote ! ( zerogc:: Trace ) ,
516
- & attrs . ignored_params ( )
525
+ & info . config . ignore_params
517
526
) ?;
518
527
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
519
528
let field_types: Vec < & Type > ;
@@ -597,7 +606,7 @@ fn impl_gc_safe(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
597
606
let name = & target. ident ;
598
607
let generics = add_trait_bounds_except (
599
608
& target. generics , parse_quote ! ( zerogc:: GcSafe ) ,
600
- & info. ignored_params ( )
609
+ & info. config . ignore_params
601
610
) ?;
602
611
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
603
612
let field_types: Vec < & Type > = match target. data {
@@ -667,7 +676,7 @@ fn impl_nop_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
667
676
let name = & target. ident ;
668
677
let generics = add_trait_bounds_except (
669
678
& target. generics , parse_quote ! ( zerogc:: Trace ) ,
670
- & info. ignored_params ( )
679
+ & info. config . ignore_params
671
680
) ?;
672
681
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
673
682
let field_types: Vec < & Type > ;
0 commit comments