allow up to 16 parameters for systems (#1805)

fixes #1772 

1st commit: the limit was at 11 as the macro was not using a range including the upper end. I changed that as it feels the purpose of the macro is clearer that way.

2nd commit: as suggested in the `// TODO`, I added a `Config` trait to go to 16 elements tuples. This means that if someone has a custom system parameter with a config that is not a tuple or an `Option`, they will have to implement `Config` for it instead of the standard `Default`.
This commit is contained in:
François 2021-04-03 23:13:54 +00:00
parent 1df3b74d38
commit 276a81cc30
4 changed files with 100 additions and 9 deletions

View file

@ -45,9 +45,9 @@ impl Parse for AllTuples {
#[proc_macro]
pub fn all_tuples(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as AllTuples);
let len = input.end - input.start;
let len = (input.start..=input.end).count();
let mut ident_tuples = Vec::with_capacity(len);
for i in input.start..input.end {
for i in input.start..=input.end {
let idents = input
.idents
.iter()
@ -64,7 +64,7 @@ pub fn all_tuples(input: TokenStream) -> TokenStream {
}
let macro_ident = &input.macro_ident;
let invocations = (input.start..input.end).map(|i| {
let invocations = (input.start..=input.end).map(|i| {
let ident_tuples = &ident_tuples[0..i];
quote! {
#macro_ident!(#(#ident_tuples),*);
@ -259,6 +259,8 @@ pub fn impl_query_set(_input: TokenStream) -> TokenStream {
.extend(&#query.archetype_component_access);
)*
}
fn default_config() {}
}
impl<'a, #(#query: WorldQuery + 'static,)* #(#filter: WorldQuery + 'static,)*> SystemParamFetch<'a> for QuerySetState<(#(QueryState<#query, #filter>,)*)>
@ -394,6 +396,10 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
fn new_archetype(&mut self, archetype: &#path::archetype::Archetype, system_state: &mut #path::system::SystemState) {
self.state.new_archetype(archetype, system_state)
}
fn default_config() -> TSystemParamState::Config {
TSystemParamState::default_config()
}
}
impl #impl_generics #path::system::SystemParamFetch<'a> for #fetch_struct_name <(#(<#field_types as SystemParam>::Fetch,)*), #punctuated_generic_idents> {

View file

@ -92,7 +92,7 @@ where
FunctionSystem {
func: self,
param_state: None,
config: Some(Default::default()),
config: Some(<Param::Fetch as SystemParamState>::default_config()),
system_state: SystemState::new::<F>(),
marker: PhantomData,
}
@ -227,4 +227,4 @@ macro_rules! impl_system_function {
};
}
all_tuples!(impl_system_function, 0, 12, F);
all_tuples!(impl_system_function, 0, 16, F);

View file

@ -38,6 +38,8 @@ mod tests {
struct B;
struct C;
struct D;
struct E;
struct F;
#[test]
fn simple_system() {
@ -435,4 +437,52 @@ mod tests {
let d_id = world.components().get_id(TypeId::of::<D>()).unwrap();
assert_eq!(conflicts, vec![b_id, d_id]);
}
#[test]
#[allow(clippy::too_many_arguments)]
fn can_have_16_parameters() {
fn sys_x(
_: Res<A>,
_: Res<B>,
_: Res<C>,
_: Res<D>,
_: Res<E>,
_: Res<F>,
_: Query<&A>,
_: Query<&B>,
_: Query<&C>,
_: Query<&D>,
_: Query<&E>,
_: Query<&F>,
_: Query<(&A, &B)>,
_: Query<(&C, &D)>,
_: Query<(&E, &F)>,
) {
}
fn sys_y(
_: (
Res<A>,
Res<B>,
Res<C>,
Res<D>,
Res<E>,
Res<F>,
Query<&A>,
Query<&B>,
Query<&C>,
Query<&D>,
Query<&E>,
Query<&F>,
Query<(&A, &B)>,
Query<(&C, &D)>,
Query<(&E, &F)>,
),
) {
}
let mut world = World::default();
let mut x = sys_x.system();
let mut y = sys_y.system();
x.initialize(&mut world);
y.initialize(&mut world);
}
}

View file

@ -42,12 +42,13 @@ pub trait SystemParam: Sized {
/// Additionally, it is the implementor's responsibility to ensure there is no
/// conflicting access across all SystemParams.
pub unsafe trait SystemParamState: Send + Sync + 'static {
type Config: Default + Send + Sync;
type Config: Send + Sync;
fn init(world: &mut World, system_state: &mut SystemState, config: Self::Config) -> Self;
#[inline]
fn new_archetype(&mut self, _archetype: &Archetype, _system_state: &mut SystemState) {}
#[inline]
fn apply(&mut self, _world: &mut World) {}
fn default_config() -> Self::Config;
}
pub trait SystemParamFetch<'a>: SystemParamState {
@ -105,6 +106,8 @@ where
.archetype_component_access
.extend(&self.archetype_component_access);
}
fn default_config() {}
}
impl<'a, Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamFetch<'a> for QueryState<Q, F>
@ -221,6 +224,8 @@ unsafe impl<T: Component> SystemParamState for ResState<T> {
marker: PhantomData,
}
}
fn default_config() {}
}
impl<'a, T: Component> SystemParamFetch<'a> for ResState<T> {
@ -262,6 +267,8 @@ unsafe impl<T: Component> SystemParamState for OptionResState<T> {
fn init(world: &mut World, system_state: &mut SystemState, _config: Self::Config) -> Self {
Self(ResState::init(world, system_state, ()))
}
fn default_config() {}
}
impl<'a, T: Component> SystemParamFetch<'a> for OptionResState<T> {
@ -367,6 +374,8 @@ unsafe impl<T: Component> SystemParamState for ResMutState<T> {
marker: PhantomData,
}
}
fn default_config() {}
}
impl<'a, T: Component> SystemParamFetch<'a> for ResMutState<T> {
@ -408,6 +417,8 @@ unsafe impl<T: Component> SystemParamState for OptionResMutState<T> {
fn init(world: &mut World, system_state: &mut SystemState, _config: Self::Config) -> Self {
Self(ResMutState::init(world, system_state, ()))
}
fn default_config() {}
}
impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState<T> {
@ -446,6 +457,8 @@ unsafe impl SystemParamState for CommandQueue {
fn apply(&mut self, world: &mut World) {
self.apply(world);
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for CommandQueue {
@ -493,6 +506,10 @@ unsafe impl<T: Component + FromWorld> SystemParamState for LocalState<T> {
fn init(world: &mut World, _system_state: &mut SystemState, config: Self::Config) -> Self {
Self(config.unwrap_or_else(|| T::from_world(world)))
}
fn default_config() -> Option<T> {
None
}
}
impl<'a, T: Component + FromWorld> SystemParamFetch<'a> for LocalState<T> {
@ -541,6 +558,8 @@ unsafe impl<T: Component> SystemParamState for RemovedComponentsState<T> {
marker: PhantomData,
}
}
fn default_config() {}
}
impl<'a, T: Component> SystemParamFetch<'a> for RemovedComponentsState<T> {
@ -630,6 +649,8 @@ unsafe impl<T: 'static> SystemParamState for NonSendState<T> {
marker: PhantomData,
}
}
fn default_config() {}
}
impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState<T> {
@ -748,6 +769,8 @@ unsafe impl<T: 'static> SystemParamState for NonSendMutState<T> {
marker: PhantomData,
}
}
fn default_config() {}
}
impl<'a, T: 'static> SystemParamFetch<'a> for NonSendMutState<T> {
@ -793,6 +816,8 @@ unsafe impl SystemParamState for ArchetypesState {
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
Self
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for ArchetypesState {
@ -822,6 +847,8 @@ unsafe impl SystemParamState for ComponentsState {
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
Self
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for ComponentsState {
@ -851,6 +878,8 @@ unsafe impl SystemParamState for EntitiesState {
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
Self
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for EntitiesState {
@ -880,6 +909,8 @@ unsafe impl SystemParamState for BundlesState {
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
Self
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for BundlesState {
@ -914,6 +945,8 @@ unsafe impl SystemParamState for SystemChangeTickState {
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
Self {}
}
fn default_config() {}
}
impl<'a> SystemParamFetch<'a> for SystemChangeTickState {
@ -976,10 +1009,12 @@ macro_rules! impl_system_param_tuple {
let ($($param,)*) = self;
$($param.apply(_world);)*
}
fn default_config() -> ($(<$param as SystemParamState>::Config,)*) {
($(<$param as SystemParamState>::default_config(),)*)
}
}
};
}
// TODO: consider creating a Config trait with a default() function, then implementing that for
// tuples. that would allow us to go past tuples of len 12
all_tuples!(impl_system_param_tuple, 0, 12, P);
all_tuples!(impl_system_param_tuple, 0, 16, P);