mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
Lift the 16-field limit from the SystemParam
derive (#6867)
# Objective * The `SystemParam` derive internally uses tuples, which means it is constrained by the 16-field limit on `all_tuples`. * The error message if you exceed this limit is abysmal. * Supercedes #5965 -- this does the same thing, but is simpler. ## Solution If any tuples have more than 16 fields, they are folded into tuples of tuples until they are under the 16-field limit.
This commit is contained in:
parent
0363e0b32a
commit
025996b18c
2 changed files with 50 additions and 5 deletions
|
@ -10,7 +10,7 @@ use proc_macro2::Span;
|
|||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
parse_macro_input, parse_quote,
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
token::Comma,
|
||||
|
@ -359,8 +359,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
)
|
||||
})
|
||||
.collect::<Vec<(&Field, SystemParamFieldAttributes)>>();
|
||||
let mut field_locals = Vec::new();
|
||||
let mut fields = Vec::new();
|
||||
let mut field_indices = Vec::new();
|
||||
let mut field_types = Vec::new();
|
||||
let mut ignored_fields = Vec::new();
|
||||
let mut ignored_field_types = Vec::new();
|
||||
|
@ -369,6 +369,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
ignored_fields.push(field.ident.as_ref().unwrap());
|
||||
ignored_field_types.push(&field.ty);
|
||||
} else {
|
||||
field_locals.push(format_ident!("f{i}"));
|
||||
let i = Index::from(i);
|
||||
fields.push(
|
||||
field
|
||||
|
@ -378,7 +379,6 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
.unwrap_or_else(|| quote! { #i }),
|
||||
);
|
||||
field_types.push(&field.ty);
|
||||
field_indices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,6 +424,19 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
_ => unreachable!(),
|
||||
}));
|
||||
|
||||
let mut tuple_types: Vec<_> = field_types.iter().map(|x| quote! { #x }).collect();
|
||||
let mut tuple_patterns: Vec<_> = field_locals.iter().map(|x| quote! { #x }).collect();
|
||||
|
||||
// If the number of fields exceeds the 16-parameter limit,
|
||||
// fold the fields into tuples of tuples until we are below the limit.
|
||||
const LIMIT: usize = 16;
|
||||
while tuple_types.len() > LIMIT {
|
||||
let end = Vec::from_iter(tuple_types.drain(..LIMIT));
|
||||
tuple_types.push(parse_quote!( (#(#end,)*) ));
|
||||
|
||||
let end = Vec::from_iter(tuple_patterns.drain(..LIMIT));
|
||||
tuple_patterns.push(parse_quote!( (#(#end,)*) ));
|
||||
}
|
||||
// Create a where clause for the `ReadOnlySystemParam` impl.
|
||||
// Ensure that each field implements `ReadOnlySystemParam`.
|
||||
let mut read_only_generics = generics.clone();
|
||||
|
@ -448,7 +461,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
|
||||
#[doc(hidden)]
|
||||
type State<'w, 's, #punctuated_generic_idents> = FetchState<
|
||||
(#(<#field_types as #path::system::SystemParam>::State,)*),
|
||||
(#(<#tuple_types as #path::system::SystemParam>::State,)*),
|
||||
#punctuated_generic_idents
|
||||
>;
|
||||
|
||||
|
@ -484,8 +497,11 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
|||
world: &'w #path::world::World,
|
||||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (#(#tuple_patterns,)*) = <
|
||||
<(#(#tuple_types,)*) as #path::system::SystemParam>::State as #path::system::SystemParamState
|
||||
>::get_param(&mut state.state, system_meta, world, change_tick);
|
||||
#struct_name {
|
||||
#(#fields: <<#field_types as #path::system::SystemParam>::State as #path::system::SystemParamState>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick),)*
|
||||
#(#fields: #field_locals,)*
|
||||
#(#ignored_fields: <#ignored_field_types>::default(),)*
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1661,6 +1661,35 @@ mod tests {
|
|||
_local: Local<'s, T>,
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct R<const I: usize>;
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub struct LongParam<'w> {
|
||||
_r0: Res<'w, R<0>>,
|
||||
_r1: Res<'w, R<1>>,
|
||||
_r2: Res<'w, R<2>>,
|
||||
_r3: Res<'w, R<3>>,
|
||||
_r4: Res<'w, R<4>>,
|
||||
_r5: Res<'w, R<5>>,
|
||||
_r6: Res<'w, R<6>>,
|
||||
_r7: Res<'w, R<7>>,
|
||||
_r8: Res<'w, R<8>>,
|
||||
_r9: Res<'w, R<9>>,
|
||||
_r10: Res<'w, R<10>>,
|
||||
_r11: Res<'w, R<11>>,
|
||||
_r12: Res<'w, R<12>>,
|
||||
_r13: Res<'w, R<13>>,
|
||||
_r14: Res<'w, R<14>>,
|
||||
_r15: Res<'w, R<15>>,
|
||||
_r16: Res<'w, R<16>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn long_system(_param: LongParam) {
|
||||
crate::system::assert_is_system(long_system);
|
||||
}
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub struct UnitParam;
|
||||
|
||||
|
|
Loading…
Reference in a new issue