@@ -12,7 +12,7 @@ use proc_macro2::Span;
12
12
use quote:: { format_ident, quote} ;
13
13
use syn:: {
14
14
parse:: ParseStream , parse_macro_input, parse_quote, punctuated:: Punctuated , spanned:: Spanned ,
15
- ConstParam , DeriveInput , Field , GenericParam , Ident , Index , Meta , MetaList , NestedMeta , Token ,
15
+ ConstParam , DeriveInput , GenericParam , Ident , Index , Meta , MetaList , NestedMeta , Token ,
16
16
TypeParam ,
17
17
} ;
18
18
@@ -259,7 +259,7 @@ static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param";
259
259
#[ proc_macro_derive( SystemParam , attributes( system_param) ) ]
260
260
pub fn derive_system_param ( input : TokenStream ) -> TokenStream {
261
261
let ast = parse_macro_input ! ( input as DeriveInput ) ;
262
- let syn:: Data :: Struct ( syn:: DataStruct { fields : field_definitions, ..} ) = ast. data else {
262
+ let syn:: Data :: Struct ( syn:: DataStruct { fields : field_definitions, .. } ) = ast. data else {
263
263
return syn:: Error :: new ( ast. span ( ) , "Invalid `SystemParam` type: expected a `struct`" )
264
264
. into_compile_error ( )
265
265
. into ( ) ;
@@ -290,7 +290,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
290
290
} ) ,
291
291
)
292
292
} )
293
- . collect :: < Vec < ( & Field , SystemParamFieldAttributes ) > > ( ) ;
293
+ . collect :: < Vec < _ > > ( ) ;
294
+
294
295
let mut field_locals = Vec :: new ( ) ;
295
296
let mut fields = Vec :: new ( ) ;
296
297
let mut field_types = Vec :: new ( ) ;
@@ -341,11 +342,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
341
342
. filter ( |g| !matches ! ( g, GenericParam :: Lifetime ( _) ) )
342
343
. collect ( ) ;
343
344
344
- let mut shadowed_lifetimes: Vec < _ > = generics. lifetimes ( ) . map ( |x| x. lifetime . clone ( ) ) . collect ( ) ;
345
- for lifetime in & mut shadowed_lifetimes {
346
- let shadowed_ident = format_ident ! ( "_{}" , lifetime. ident) ;
347
- lifetime. ident = shadowed_ident;
348
- }
345
+ let shadowed_lifetimes: Vec < _ > = generics. lifetimes ( ) . map ( |_| quote ! ( ' _) ) . collect ( ) ;
349
346
350
347
let mut punctuated_generics = Punctuated :: < _ , Token ! [ , ] > :: new ( ) ;
351
348
punctuated_generics. extend ( lifetimeless_generics. iter ( ) . map ( |g| match g {
@@ -367,9 +364,27 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
367
364
_ => unreachable ! ( ) ,
368
365
} ) ) ;
369
366
367
+ let punctuated_generics_no_bounds: Punctuated < _ , Token ! [ , ] > = lifetimeless_generics
368
+ . iter ( )
369
+ . map ( |& g| match g. clone ( ) {
370
+ GenericParam :: Type ( mut g) => {
371
+ g. bounds . clear ( ) ;
372
+ GenericParam :: Type ( g)
373
+ }
374
+ g => g,
375
+ } )
376
+ . collect ( ) ;
377
+
370
378
let mut tuple_types: Vec < _ > = field_types. iter ( ) . map ( |x| quote ! { #x } ) . collect ( ) ;
371
379
let mut tuple_patterns: Vec < _ > = field_locals. iter ( ) . map ( |x| quote ! { #x } ) . collect ( ) ;
372
380
381
+ tuple_types. extend (
382
+ ignored_field_types
383
+ . iter ( )
384
+ . map ( |ty| parse_quote ! ( :: std:: marker:: PhantomData :: <#ty>) ) ,
385
+ ) ;
386
+ tuple_patterns. extend ( ignored_field_types. iter ( ) . map ( |_| parse_quote ! ( _) ) ) ;
387
+
373
388
// If the number of fields exceeds the 16-parameter limit,
374
389
// fold the fields into tuples of tuples until we are below the limit.
375
390
const LIMIT : usize = 16 ;
@@ -380,6 +395,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
380
395
let end = Vec :: from_iter ( tuple_patterns. drain ( ..LIMIT ) ) ;
381
396
tuple_patterns. push ( parse_quote ! ( ( #( #end, ) * ) ) ) ;
382
397
}
398
+
383
399
// Create a where clause for the `ReadOnlySystemParam` impl.
384
400
// Ensure that each field implements `ReadOnlySystemParam`.
385
401
let mut read_only_generics = generics. clone ( ) ;
@@ -390,6 +406,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
390
406
. push ( syn:: parse_quote!( #field_type: #path:: system:: ReadOnlySystemParam ) ) ;
391
407
}
392
408
409
+ let fields_alias = format_ident ! ( "__StructFieldsAlias" ) ;
410
+
393
411
let struct_name = & ast. ident ;
394
412
let state_struct_visibility = & ast. vis ;
395
413
@@ -398,41 +416,41 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
398
416
// The struct can still be accessed via SystemParam::State, e.g. EventReaderState can be accessed via
399
417
// <EventReader<'static, 'static, T> as SystemParam>::State
400
418
const _: ( ) = {
419
+ // Allows rebinding the lifetimes of each field type.
420
+ type #fields_alias <' w, ' s, #punctuated_generics_no_bounds> = ( #( #tuple_types, ) * ) ;
421
+
401
422
#[ doc( hidden) ]
402
- #state_struct_visibility struct FetchState <' w , ' s , #( #lifetimeless_generics, ) * >
423
+ #state_struct_visibility struct FetchState <#( #lifetimeless_generics, ) * >
403
424
#where_clause {
404
- state: ( #( <#tuple_types as #path:: system:: SystemParam >:: State , ) * ) ,
405
- marker: std:: marker:: PhantomData <(
406
- <#path:: prelude:: Query <' w, ' s, ( ) > as #path:: system:: SystemParam >:: State ,
407
- #( fn ( ) -> #ignored_field_types, ) *
408
- ) >,
425
+ state: <#fields_alias:: <' static , ' static , #punctuated_generic_idents> as #path:: system:: SystemParam >:: State ,
409
426
}
410
427
411
- unsafe impl <' w, ' s, #punctuated_generics> #path:: system:: SystemParam for #struct_name #ty_generics #where_clause {
412
- type State = FetchState <' static , ' static , #punctuated_generic_idents>;
413
- type Item <' _w, ' _s> = #struct_name <#( #shadowed_lifetimes, ) * #punctuated_generic_idents>;
428
+ unsafe impl <#punctuated_generics> #path:: system:: SystemParam for
429
+ #struct_name <#( #shadowed_lifetimes, ) * #punctuated_generic_idents> #where_clause
430
+ {
431
+ type State = FetchState <#punctuated_generic_idents>;
432
+ type Item <' w, ' s> = #struct_name #ty_generics;
414
433
415
434
fn init_state( world: & mut #path:: world:: World , system_meta: & mut #path:: system:: SystemMeta ) -> Self :: State {
416
435
FetchState {
417
- state: <( #( #tuple_types, ) * ) as #path:: system:: SystemParam >:: init_state( world, system_meta) ,
418
- marker: std:: marker:: PhantomData ,
436
+ state: <#fields_alias:: <' _, ' _, #punctuated_generic_idents> as #path:: system:: SystemParam >:: init_state( world, system_meta) ,
419
437
}
420
438
}
421
439
422
440
fn new_archetype( state: & mut Self :: State , archetype: & #path:: archetype:: Archetype , system_meta: & mut #path:: system:: SystemMeta ) {
423
- <( # ( #tuple_types , ) * ) as #path:: system:: SystemParam >:: new_archetype( & mut state. state, archetype, system_meta)
441
+ <#fields_alias :: < ' _ , ' _ , #punctuated_generic_idents> as #path:: system:: SystemParam >:: new_archetype( & mut state. state, archetype, system_meta)
424
442
}
425
443
426
444
fn apply( state: & mut Self :: State , system_meta: & #path:: system:: SystemMeta , world: & mut #path:: world:: World ) {
427
- <( # ( #tuple_types , ) * ) as #path:: system:: SystemParam >:: apply( & mut state. state, system_meta, world) ;
445
+ <#fields_alias :: < ' _ , ' _ , #punctuated_generic_idents> as #path:: system:: SystemParam >:: apply( & mut state. state, system_meta, world) ;
428
446
}
429
447
430
- unsafe fn get_param<' w2 , ' s2 >(
431
- state: & ' s2 mut Self :: State ,
448
+ unsafe fn get_param<' w , ' s >(
449
+ state: & ' s mut Self :: State ,
432
450
system_meta: & #path:: system:: SystemMeta ,
433
- world: & ' w2 #path:: world:: World ,
451
+ world: & ' w #path:: world:: World ,
434
452
change_tick: u32 ,
435
- ) -> Self :: Item <' w2 , ' s2 > {
453
+ ) -> Self :: Item <' w , ' s > {
436
454
let ( #( #tuple_patterns, ) * ) = <
437
455
( #( #tuple_types, ) * ) as #path:: system:: SystemParam
438
456
>:: get_param( & mut state. state, system_meta, world, change_tick) ;
0 commit comments