From b582c5d6fa9cf4ecedfe17bebe903a21d2945989 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 11 Nov 2022 03:09:16 -0500 Subject: [PATCH 1/5] support `In`/`Out` for exclusive systems --- .../src/system/exclusive_function_system.rs | 89 ++++++++++++++----- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index 8b1607c75898e..c6fe8acba1fcf 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -6,7 +6,8 @@ use crate::{ schedule::{SystemLabel, SystemLabelId}, system::{ check_system_change_tick, AsSystemLabel, ExclusiveSystemParam, ExclusiveSystemParamItem, - ExclusiveSystemParamState, IntoSystem, System, SystemMeta, SystemTypeIdLabel, + ExclusiveSystemParamState, In, InputMarker, IntoSystem, System, SystemMeta, + SystemTypeIdLabel, }, world::{World, WorldId}, }; @@ -19,7 +20,7 @@ use std::{borrow::Cow, marker::PhantomData}; /// [`ExclusiveSystemParam`]s. /// /// [`ExclusiveFunctionSystem`] must be `.initialized` before they can be run. -pub struct ExclusiveFunctionSystem +pub struct ExclusiveFunctionSystem where Param: ExclusiveSystemParam, { @@ -28,18 +29,21 @@ where system_meta: SystemMeta, world_id: Option, // NOTE: PhantomData T> gives this safe Send/Sync impls - marker: PhantomData Marker>, + marker: PhantomData (In, Out, Marker)>, } pub struct IsExclusiveFunctionSystem; -impl IntoSystem<(), (), (IsExclusiveFunctionSystem, Param, Marker)> for F +impl IntoSystem + for F where + In: 'static, + Out: 'static, Param: ExclusiveSystemParam + 'static, Marker: 'static, - F: ExclusiveSystemParamFunction + Send + Sync + 'static, + F: ExclusiveSystemParamFunction + Send + Sync + 'static, { - type System = ExclusiveFunctionSystem; + type System = ExclusiveFunctionSystem; fn into_system(func: Self) -> Self::System { ExclusiveFunctionSystem { func, @@ -53,14 +57,16 @@ where const PARAM_MESSAGE: &str = "System's param_state was not found. Did you forget to initialize this system before running it?"; -impl System for ExclusiveFunctionSystem +impl System for ExclusiveFunctionSystem where + In: 'static, + Out: 'static, Param: ExclusiveSystemParam + 'static, Marker: 'static, - F: ExclusiveSystemParamFunction + Send + Sync + 'static, + F: ExclusiveSystemParamFunction + Send + Sync + 'static, { - type In = (); - type Out = (); + type In = In; + type Out = Out; #[inline] fn name(&self) -> Cow<'static, str> { @@ -90,7 +96,7 @@ where panic!("Cannot run exclusive systems with a shared World reference"); } - fn run(&mut self, _input: Self::In, world: &mut World) -> Self::Out { + fn run(&mut self, input: Self::In, world: &mut World) -> Self::Out { let saved_last_tick = world.last_change_tick; world.last_change_tick = self.system_meta.last_change_tick; @@ -98,12 +104,14 @@ where self.param_state.as_mut().expect(PARAM_MESSAGE), &self.system_meta, ); - self.func.run(world, params); + let out = self.func.run(world, input, params); let change_tick = world.change_tick.get_mut(); self.system_meta.last_change_tick = *change_tick; *change_tick += 1; world.last_change_tick = saved_last_tick; + + out } #[inline] @@ -150,8 +158,11 @@ where } } -impl> - AsSystemLabel<(Param, Marker, IsExclusiveFunctionSystem)> for T +impl AsSystemLabel<(In, Out, Param, Marker, IsExclusiveFunctionSystem)> + for T +where + Param: ExclusiveSystemParam, + T: ExclusiveSystemParamFunction, { #[inline] fn as_system_label(&self) -> SystemLabelId { @@ -163,38 +174,70 @@ impl: +pub trait ExclusiveSystemParamFunction: Send + Sync + 'static { - fn run(&mut self, world: &mut World, param_value: ExclusiveSystemParamItem); + fn run( + &mut self, + world: &mut World, + input: In, + param_value: ExclusiveSystemParamItem, + ) -> Out; } macro_rules! impl_exclusive_system_function { ($($param: ident),*) => { #[allow(non_snake_case)] - impl ExclusiveSystemParamFunction<($($param,)*), ()> for Func + impl ExclusiveSystemParamFunction<(), Out, ($($param,)*), ()> for Func where for <'a> &'a mut Func: - FnMut(&mut World, $($param),*) + - FnMut(&mut World, $(ExclusiveSystemParamItem<$param>),*) + FnMut(&mut World, $($param),*) -> Out + + FnMut(&mut World, $(ExclusiveSystemParamItem<$param>),*) -> Out, + Out: 'static, { #[inline] - fn run(&mut self, world: &mut World, param_value: ExclusiveSystemParamItem< ($($param,)*)>) { + fn run(&mut self, world: &mut World, _in: (), param_value: ExclusiveSystemParamItem< ($($param,)*)>) -> Out { // Yes, this is strange, but `rustc` fails to compile this impl // without using this function. It fails to recognise that `func` // is a function, potentially because of the multiple impls of `FnMut` #[allow(clippy::too_many_arguments)] - fn call_inner<$($param,)*>( - mut f: impl FnMut(&mut World, $($param,)*), + fn call_inner( + mut f: impl FnMut(&mut World, $($param,)*) -> Out, world: &mut World, $($param: $param,)* - ) { + ) -> Out { f(world, $($param,)*) } let ($($param,)*) = param_value; call_inner(self, world, $($param),*) } } + #[allow(non_snake_case)] + impl ExclusiveSystemParamFunction for Func + where + for <'a> &'a mut Func: + FnMut(&mut World, In, $($param),*) -> Out + + FnMut(&mut World, In, $(ExclusiveSystemParamItem<$param>),*) -> Out, + Out: 'static, + { + #[inline] + fn run(&mut self, world: &mut World, input: Input, param_value: ExclusiveSystemParamItem< ($($param,)*)>) -> Out { + // Yes, this is strange, but `rustc` fails to compile this impl + // without using this function. It fails to recognise that `func` + // is a function, potentially because of the multiple impls of `FnMut` + #[allow(clippy::too_many_arguments)] + fn call_inner( + mut f: impl FnMut(&mut World, In, $($param,)*) -> Out, + world: &mut World, + input: Input, + $($param: $param,)* + ) -> Out { + f(world, In(input), $($param,)*) + } + let ($($param,)*) = param_value; + call_inner(self, world, input, $($param),*) + } + } }; } // Note that we rely on the highest impl to be <= the highest order of the tuple impls From 05e68a93ad2d1e429bae9163a941b84865828e97 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sat, 24 Dec 2022 08:58:18 -0500 Subject: [PATCH 2/5] add a test case for piping exclusive systems --- crates/bevy_ecs/src/system/system_piping.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index d28158b697836..fc89e10a7c561 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -423,8 +423,15 @@ pub mod adapter { unimplemented!() } + /// Mocks an exclusive system that returns a value of type `T`. + fn exclusive_in_out(_: &mut World, _: In) -> B { + unimplemented!() + } + assert_is_system(returning::>.pipe(unwrap)); assert_is_system(returning::>.pipe(ignore)); assert_is_system(returning::<&str>.pipe(new(u64::from_str)).pipe(unwrap)); + assert_is_system(exclusive_in_out::<(), Result<(), std::io::Error>>.pipe(error)); + assert_is_system(returning::.pipe(exclusive_in_out::)); } } From c36a63719b99f9b667b65d5223b51d18c27b2e93 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sat, 24 Dec 2022 09:00:20 -0500 Subject: [PATCH 3/5] put `In` before `&mut World` --- .../bevy_ecs/src/system/exclusive_function_system.rs | 12 ++++++------ crates/bevy_ecs/src/system/system_piping.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index c6fe8acba1fcf..ea0aaec7a83a3 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -216,8 +216,8 @@ macro_rules! impl_exclusive_system_function { impl ExclusiveSystemParamFunction for Func where for <'a> &'a mut Func: - FnMut(&mut World, In, $($param),*) -> Out + - FnMut(&mut World, In, $(ExclusiveSystemParamItem<$param>),*) -> Out, + FnMut(In, &mut World, $($param),*) -> Out + + FnMut(In, &mut World, $(ExclusiveSystemParamItem<$param>),*) -> Out, Out: 'static, { #[inline] @@ -227,15 +227,15 @@ macro_rules! impl_exclusive_system_function { // is a function, potentially because of the multiple impls of `FnMut` #[allow(clippy::too_many_arguments)] fn call_inner( - mut f: impl FnMut(&mut World, In, $($param,)*) -> Out, - world: &mut World, + mut f: impl FnMut(In, &mut World, $($param,)*) -> Out, input: Input, + world: &mut World, $($param: $param,)* ) -> Out { - f(world, In(input), $($param,)*) + f(In(input), world, $($param,)*) } let ($($param,)*) = param_value; - call_inner(self, world, input, $($param),*) + call_inner(self, input, world, $($param),*) } } }; diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index fc89e10a7c561..0265affc390f2 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -424,7 +424,7 @@ pub mod adapter { } /// Mocks an exclusive system that returns a value of type `T`. - fn exclusive_in_out(_: &mut World, _: In) -> B { + fn exclusive_in_out(_: In, _: &mut World) -> B { unimplemented!() } From 043ec9d2e159f5f5320785debcdc654c90b5e35b Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sat, 24 Dec 2022 09:02:48 -0500 Subject: [PATCH 4/5] update a comment --- crates/bevy_ecs/src/system/system_piping.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/system/system_piping.rs b/crates/bevy_ecs/src/system/system_piping.rs index 0265affc390f2..bfcb2c530b3fe 100644 --- a/crates/bevy_ecs/src/system/system_piping.rs +++ b/crates/bevy_ecs/src/system/system_piping.rs @@ -423,7 +423,7 @@ pub mod adapter { unimplemented!() } - /// Mocks an exclusive system that returns a value of type `T`. + /// Mocks an exclusive system that takes an input and returns an output. fn exclusive_in_out(_: In, _: &mut World) -> B { unimplemented!() } From b5bdf113a9361e7ef2654786ca656e2124a42563 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sat, 24 Dec 2022 09:45:09 -0500 Subject: [PATCH 5/5] use contravariant inputs --- crates/bevy_ecs/src/system/exclusive_function_system.rs | 2 +- crates/bevy_ecs/src/system/function_system.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/system/exclusive_function_system.rs b/crates/bevy_ecs/src/system/exclusive_function_system.rs index ea0aaec7a83a3..fe42770df13c9 100644 --- a/crates/bevy_ecs/src/system/exclusive_function_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_function_system.rs @@ -29,7 +29,7 @@ where system_meta: SystemMeta, world_id: Option, // NOTE: PhantomData T> gives this safe Send/Sync impls - marker: PhantomData (In, Out, Marker)>, + marker: PhantomData (Out, Marker)>, } pub struct IsExclusiveFunctionSystem; diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 2cc88f9e30b77..9f199eda42192 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -320,7 +320,7 @@ where world_id: Option, archetype_generation: ArchetypeGeneration, // NOTE: PhantomData T> gives this safe Send/Sync impls - marker: PhantomData (In, Out, Marker)>, + marker: PhantomData (Out, Marker)>, } pub struct IsFunctionSystem;