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