@@ -10,7 +10,7 @@ use proc_macro2::Span;
1010use quote:: { format_ident, quote} ;
1111use syn:: {
1212 parse:: { Parse , ParseStream } ,
13- parse_macro_input,
13+ parse_macro_input, parse_quote ,
1414 punctuated:: Punctuated ,
1515 spanned:: Spanned ,
1616 token:: Comma ,
@@ -359,8 +359,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
359359 )
360360 } )
361361 . collect :: < Vec < ( & Field , SystemParamFieldAttributes ) > > ( ) ;
362+ let mut field_locals = Vec :: new ( ) ;
362363 let mut fields = Vec :: new ( ) ;
363- let mut field_indices = Vec :: new ( ) ;
364364 let mut field_types = Vec :: new ( ) ;
365365 let mut ignored_fields = Vec :: new ( ) ;
366366 let mut ignored_field_types = Vec :: new ( ) ;
@@ -369,6 +369,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
369369 ignored_fields. push ( field. ident . as_ref ( ) . unwrap ( ) ) ;
370370 ignored_field_types. push ( & field. ty ) ;
371371 } else {
372+ field_locals. push ( format_ident ! ( "f{i}" ) ) ;
372373 let i = Index :: from ( i) ;
373374 fields. push (
374375 field
@@ -378,7 +379,6 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
378379 . unwrap_or_else ( || quote ! { #i } ) ,
379380 ) ;
380381 field_types. push ( & field. ty ) ;
381- field_indices. push ( i) ;
382382 }
383383 }
384384
@@ -424,6 +424,19 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
424424 _ => unreachable ! ( ) ,
425425 } ) ) ;
426426
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+ }
427440 // Create a where clause for the `ReadOnlySystemParam` impl.
428441 // Ensure that each field implements `ReadOnlySystemParam`.
429442 let mut read_only_generics = generics. clone ( ) ;
@@ -448,7 +461,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
448461
449462 #[ doc( hidden) ]
450463 type State <' w, ' s, #punctuated_generic_idents> = FetchState <
451- ( #( <#field_types as #path:: system:: SystemParam >:: State , ) * ) ,
464+ ( #( <#tuple_types as #path:: system:: SystemParam >:: State , ) * ) ,
452465 #punctuated_generic_idents
453466 >;
454467
@@ -484,8 +497,11 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
484497 world: & ' w #path:: world:: World ,
485498 change_tick: u32 ,
486499 ) -> 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) ;
487503 #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 , ) *
489505 #( #ignored_fields: <#ignored_field_types>:: default ( ) , ) *
490506 }
491507 }
0 commit comments