1
- use quote:: quote;
1
+ use quote:: { quote, format_ident } ;
2
2
use syn:: { parenthesized, Token , parse_quote, DeriveInput , Data , Generics , GenericParam , TypeParamBound , DataEnum , DataStruct , DataUnion , Type } ;
3
3
use proc_macro2:: { TokenStream , Ident , Span } ;
4
4
use syn:: parse:: { self , Parse , ParseStream } ;
@@ -154,16 +154,24 @@ fn handle_type<'a, T: TypeHandler<'a>>(
154
154
where_clause : TokenStream ,
155
155
extra_defs : & mut Vec < TokenStream >
156
156
) -> Result < TokenStream , syn:: Error > {
157
- let mut field_info: IndexMap < Ident , TokenStream > = IndexMap :: new ( ) ;
157
+ let mut field_info: IndexMap < FieldName < ' a > , TokenStream > = IndexMap :: new ( ) ;
158
158
let mut field_associated_types = Vec :: new ( ) ;
159
159
let mut field_defs = Vec :: new ( ) ;
160
160
target. handle_fields ( |field| {
161
161
let field_name = field. name ;
162
162
let field_type = & field. static_type ;
163
163
field_info. insert ( field_name. clone ( ) , field. static_def . clone ( ) ) ;
164
- field_associated_types. push ( quote ! ( type #field_name = #field_type; ) ) ;
164
+ let associated_type_name = field_name. associated_type_name ( ) ;
165
+ field_associated_types. push ( quote ! ( type #associated_type_name = #field_type; ) ) ;
165
166
let field_def_type = T :: field_def_type ( Some ( quote ! ( #field_type) ) ) ;
166
- field_defs. push ( quote ! ( pub #field_name: #field_def_type, ) ) ;
167
+ match field_name {
168
+ FieldName :: Tuple { index : _ } => {
169
+ field_defs. push ( quote ! ( pub #field_def_type) ) ;
170
+ }
171
+ FieldName :: Named { name } => {
172
+ field_defs. push ( quote ! ( pub #name: #field_def_type) ) ;
173
+ }
174
+ }
167
175
} ) ?;
168
176
let field_info_struct_name = Ident :: new (
169
177
& format ! ( "_FieldInfo{}" , name) ,
@@ -173,43 +181,59 @@ fn handle_type<'a, T: TypeHandler<'a>>(
173
181
& format ! ( "_FieldTrait{}" , name) ,
174
182
name. span ( )
175
183
) ;
176
- let field_names = field_info. keys ( ) . collect :: < Vec < _ > > ( ) ;
177
- extra_defs. push ( quote ! (
178
- #[ allow( missing_docs) ]
179
- #[ doc( hidden) ]
180
- pub struct #field_info_struct_name {
181
- #( #field_defs) *
184
+ let associated_type_names = field_info. keys ( ) . map ( FieldName :: associated_type_name) ;
185
+ let field_info_struct_def = {
186
+ let fields = quote ! ( #( #field_defs) , * ) ;
187
+ let fields = if target. is_tuple_style ( ) {
188
+ // NOTE: I guess a tuple-struct needs a semicolon but a regular struct doesn't....
189
+ quote ! ( ( #fields) ; )
190
+ } else {
191
+ quote ! ( { #fields } )
192
+ } ;
193
+ quote ! {
194
+ #[ allow( missing_docs) ]
195
+ #[ doc( hidden) ]
196
+ pub struct #field_info_struct_name #fields
182
197
}
198
+ } ;
199
+ extra_defs. push ( quote ! (
200
+ #field_info_struct_def
183
201
#[ allow( non_camel_case_types) ]
184
202
#[ doc( hidden) ]
185
203
trait #field_info_trait_name {
186
- #( type #field_names ; ) *
204
+ #( type #associated_type_names ; ) *
187
205
}
188
206
#[ allow( non_camel_case_types) ]
189
207
impl #impl_generics #field_info_trait_name for #name #ty_generics #where_clause {
190
208
#( #field_associated_types) *
191
209
}
192
210
) ) ;
193
211
let field_inits = field_info. iter ( )
194
- . map ( |( name, def) | quote ! ( #name: #def, ) )
212
+ . map ( |( name, def) | match name {
213
+ FieldName :: Tuple { .. } => quote ! ( #def) ,
214
+ FieldName :: Named { name } => quote ! ( #name: #def)
215
+ } )
195
216
. collect :: < Vec < TokenStream > > ( ) ;
217
+ let field_inits = if target. is_tuple_style ( ) {
218
+ quote ! ( ( #( #field_inits, ) * ) )
219
+ } else {
220
+ quote ! ( { #( #field_inits, ) * } )
221
+ } ;
196
222
extra_defs. push ( quote ! (
197
223
unsafe impl #impl_generics static_reflect:: FieldReflect for #name #ty_generics #where_clause {
198
224
type NamedFieldInfo = #field_info_struct_name;
199
- const NAMED_FIELD_INFO : Self :: NamedFieldInfo = #field_info_struct_name {
200
- #( #field_inits) *
201
- } ;
225
+ const NAMED_FIELD_INFO : Self :: NamedFieldInfo = #field_info_struct_name #field_inits;
202
226
}
203
227
) ) ;
204
- let field_names = field_info. keys ( ) . collect :: < Vec < _ > > ( ) ;
228
+ let field_access = field_info. keys ( ) . map ( |name| name . access ( ) ) . collect :: < Vec < _ > > ( ) ;
205
229
let field_def_type_name = T :: field_def_type ( None ) ;
206
230
let type_def_type = T :: type_def_type ( ) ;
207
231
let header = quote ! {
208
232
use static_reflect:: { StaticReflect , FieldReflect } ;
209
233
use static_reflect:: types:: TypeInfo ;
210
234
use #field_def_type_name;
211
235
use #type_def_type;
212
- const _FIELDS: & ' static [ #field_def_type_name<' static >] = & [ #( <#name as FieldReflect >:: NAMED_FIELD_INFO . #field_names . erase( ) ) , * ] ;
236
+ const _FIELDS: & ' static [ #field_def_type_name<' static >] = & [ #( <#name as FieldReflect >:: NAMED_FIELD_INFO . #field_access . erase( ) ) , * ] ;
213
237
} ;
214
238
let static_def = target. create_static_def ( header) ;
215
239
let into_type = T :: def_into_type ( quote ! ( _DEF) ) ;
@@ -232,14 +256,41 @@ fn enum_static_type(data: &DataEnum, name: &Ident) -> Result<TokenStream, syn::E
232
256
}
233
257
}
234
258
trait TypeHandler < ' a > {
259
+ fn is_tuple_style ( & self ) -> bool ;
235
260
fn field_def_type ( field_type : Option < TokenStream > ) -> TokenStream ;
236
261
fn type_def_type ( ) -> TokenStream ;
237
262
fn def_into_type ( def_ref : TokenStream ) -> TokenStream ;
238
263
fn handle_fields < F : FnMut ( FieldInfo < ' a > ) > ( & mut self , handler : F ) -> syn:: Result < ( ) > ;
239
264
fn create_static_def ( self , header : TokenStream ) -> TokenStream ;
240
265
}
266
+ #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
267
+ pub enum FieldName < ' a > {
268
+ Tuple {
269
+ index : usize ,
270
+ } ,
271
+ Named {
272
+ name : & ' a Ident
273
+ }
274
+ }
275
+ impl FieldName < ' _ > {
276
+ pub fn access ( & self ) -> TokenStream {
277
+ match * self {
278
+ FieldName :: Tuple { index } => {
279
+ let idx = syn:: Index :: from ( index) ;
280
+ quote ! ( #idx)
281
+ } ,
282
+ FieldName :: Named { name } => quote ! ( #name) ,
283
+ }
284
+ }
285
+ pub fn associated_type_name ( & self ) -> Ident {
286
+ match * self {
287
+ FieldName :: Tuple { index } => format_ident ! ( "_Tuple_{}" , index) ,
288
+ FieldName :: Named { name } => name. clone ( )
289
+ }
290
+ }
291
+ }
241
292
struct FieldInfo < ' a > {
242
- name : & ' a Ident ,
293
+ name : FieldName < ' a > ,
243
294
static_type : Type ,
244
295
static_def : TokenStream
245
296
}
@@ -256,6 +307,9 @@ impl<'a> StructHandler<'a> {
256
307
}
257
308
}
258
309
impl < ' a > TypeHandler < ' a > for StructHandler < ' a > {
310
+ fn is_tuple_style ( & self ) -> bool {
311
+ matches ! ( self . data. fields, syn:: Fields :: Unnamed ( _) )
312
+ }
259
313
260
314
fn field_def_type ( field_type : Option < TokenStream > ) -> TokenStream {
261
315
match field_type {
@@ -274,15 +328,18 @@ impl<'a> TypeHandler<'a> for StructHandler<'a> {
274
328
275
329
fn handle_fields < F : FnMut ( FieldInfo < ' a > ) > ( & mut self , mut handler : F ) -> syn:: Result < ( ) > {
276
330
/*
277
- * NOTE: Layout algorithim for repr(C) given in reference
331
+ * NOTE: Layout algorithm for repr(C) given in reference
278
332
* https://doc.rust-lang.org/reference/type-layout.html#reprc-structs
279
333
* We have to use recursion to compute offsets :(
280
334
*/
281
335
let mut current_offset = self . current_offset . clone ( ) ;
282
336
for ( index, field) in self . data . fields . iter ( ) . enumerate ( ) {
283
337
let DeriveFieldOptions { opaque_array, assume_repr } =
284
338
DeriveFieldOptions :: parse_attrs ( & field. attrs ) ?;
285
- let field_name = field. ident . as_ref ( ) . expect ( "Need named fields" ) ;
339
+ let field_name = match field. ident {
340
+ Some ( ref name) => FieldName :: Named { name } ,
341
+ None => FieldName :: Tuple { index }
342
+ } ;
286
343
let mut field_type = field. ty . clone ( ) ;
287
344
let original_type = field_type. clone ( ) ;
288
345
if opaque_array {
@@ -320,8 +377,12 @@ impl<'a> TypeHandler<'a> for StructHandler<'a> {
320
377
let rem = old_offset % std:: mem:: align_of:: <#original_type>( ) ;
321
378
old_offset + ( if rem == 0 { 0 } else { std:: mem:: align_of:: <#original_type>( ) - rem } )
322
379
} ) ;
380
+ let name_field_value = match field_name {
381
+ FieldName :: Tuple { .. } => quote ! ( None ) ,
382
+ FieldName :: Named { name } => quote ! ( Some ( stringify!( #name) ) )
383
+ } ;
323
384
let static_def = quote ! ( :: static_reflect:: types:: FieldDef {
324
- name: stringify! ( #field_name ) ,
385
+ name: #name_field_value ,
325
386
value_type: :: static_reflect:: types:: TypeId :: <#field_type>:: get( ) ,
326
387
offset: #current_offset,
327
388
index: #index
@@ -378,6 +439,10 @@ struct UnionTypeHandler<'a> {
378
439
name : & ' a Ident
379
440
}
380
441
impl < ' a > TypeHandler < ' a > for UnionTypeHandler < ' a > {
442
+ fn is_tuple_style ( & self ) -> bool {
443
+ false // unions can't have tuple-fields
444
+ }
445
+
381
446
fn field_def_type ( field_type : Option < TokenStream > ) -> TokenStream {
382
447
match field_type {
383
448
None => quote ! ( static_reflect:: types:: UnionFieldDef ) ,
@@ -395,7 +460,7 @@ impl<'a> TypeHandler<'a> for UnionTypeHandler<'a> {
395
460
396
461
fn handle_fields < F : FnMut ( FieldInfo < ' a > ) > ( & mut self , mut handler : F ) -> syn:: Result < ( ) > {
397
462
/*
398
- * NOTE: Layout algorithim for repr(C) given in reference
463
+ * NOTE: Layout algorithm for repr(C) given in reference
399
464
* https://doc.rust-lang.org/reference/type-layout.html#reprc-unions
400
465
*
401
466
* Unions are pretty simple since they're just glorified `mem::transmute`
@@ -420,7 +485,7 @@ impl<'a> TypeHandler<'a> for UnionTypeHandler<'a> {
420
485
index: #index
421
486
} ) ;
422
487
handler ( FieldInfo {
423
- name : field_name,
488
+ name : FieldName :: Named { name : field_name } ,
424
489
static_type : field_type,
425
490
static_def
426
491
} ) ;
0 commit comments