@@ -10,7 +10,7 @@ use proc_macro2::Span;
10
10
use quote:: { format_ident, quote} ;
11
11
use syn:: {
12
12
parse:: { Parse , ParseStream } ,
13
- parse_macro_input,
13
+ parse_macro_input, parse_quote ,
14
14
punctuated:: Punctuated ,
15
15
spanned:: Spanned ,
16
16
token:: Comma ,
@@ -359,8 +359,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
359
359
)
360
360
} )
361
361
. collect :: < Vec < ( & Field , SystemParamFieldAttributes ) > > ( ) ;
362
+ let mut field_locals = Vec :: new ( ) ;
362
363
let mut fields = Vec :: new ( ) ;
363
- let mut field_indices = Vec :: new ( ) ;
364
364
let mut field_types = Vec :: new ( ) ;
365
365
let mut ignored_fields = Vec :: new ( ) ;
366
366
let mut ignored_field_types = Vec :: new ( ) ;
@@ -369,6 +369,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
369
369
ignored_fields. push ( field. ident . as_ref ( ) . unwrap ( ) ) ;
370
370
ignored_field_types. push ( & field. ty ) ;
371
371
} else {
372
+ field_locals. push ( format_ident ! ( "f{i}" ) ) ;
372
373
let i = Index :: from ( i) ;
373
374
fields. push (
374
375
field
@@ -378,7 +379,6 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
378
379
. unwrap_or_else ( || quote ! { #i } ) ,
379
380
) ;
380
381
field_types. push ( & field. ty ) ;
381
- field_indices. push ( i) ;
382
382
}
383
383
}
384
384
@@ -424,6 +424,19 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
424
424
_ => unreachable ! ( ) ,
425
425
} ) ) ;
426
426
427
+ let mut tuple_types: Vec < _ > = field_types. iter ( ) . map ( |x| quote ! { #x } ) . collect ( ) ;
428
+ let mut tuple_patterns: Vec < _ > = field_locals. iter ( ) . map ( |x| quote ! { #x } ) . collect ( ) ;
429
+
430
+ // If the number of fields exceeds the 16-parameter limit,
431
+ // fold the fields into tuples of tuples until we are below the limit.
432
+ const LIMIT : usize = 16 ;
433
+ while tuple_types. len ( ) > LIMIT {
434
+ let end = Vec :: from_iter ( tuple_types. drain ( ..LIMIT ) ) ;
435
+ tuple_types. push ( parse_quote ! ( ( #( #end, ) * ) ) ) ;
436
+
437
+ let end = Vec :: from_iter ( tuple_patterns. drain ( ..LIMIT ) ) ;
438
+ tuple_patterns. push ( parse_quote ! ( ( #( #end, ) * ) ) ) ;
439
+ }
427
440
// Create a where clause for the `ReadOnlySystemParam` impl.
428
441
// Ensure that each field implements `ReadOnlySystemParam`.
429
442
let mut read_only_generics = generics. clone ( ) ;
@@ -448,7 +461,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
448
461
449
462
#[ doc( hidden) ]
450
463
type State <' w, ' s, #punctuated_generic_idents> = FetchState <
451
- ( #( <#field_types as #path:: system:: SystemParam >:: State , ) * ) ,
464
+ ( #( <#tuple_types as #path:: system:: SystemParam >:: State , ) * ) ,
452
465
#punctuated_generic_idents
453
466
>;
454
467
@@ -484,8 +497,11 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
484
497
world: & ' w #path:: world:: World ,
485
498
change_tick: u32 ,
486
499
) -> Self :: Item <' w, ' s> {
500
+ let ( #( #tuple_patterns, ) * ) = <
501
+ <( #( #tuple_types, ) * ) as #path:: system:: SystemParam >:: State as #path:: system:: SystemParamState
502
+ >:: get_param( & mut state. state, system_meta, world, change_tick) ;
487
503
#struct_name {
488
- #( #fields: <<#field_types as #path :: system :: SystemParam > :: State as #path :: system :: SystemParamState > :: get_param ( & mut state . state . #field_indices , system_meta , world , change_tick ) , ) *
504
+ #( #fields: #field_locals , ) *
489
505
#( #ignored_fields: <#ignored_field_types>:: default ( ) , ) *
490
506
}
491
507
}
0 commit comments