-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - Support piping exclusive systems #7023
Changes from 4 commits
b582c5d
05e68a9
c36a637
043ec9d
b5bdf11
2071998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<Param, Marker, F> | ||
pub struct ExclusiveFunctionSystem<In, Out, Param, Marker, F> | ||
where | ||
Param: ExclusiveSystemParam, | ||
{ | ||
|
@@ -28,18 +29,21 @@ where | |
system_meta: SystemMeta, | ||
world_id: Option<WorldId>, | ||
// NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls | ||
marker: PhantomData<fn() -> Marker>, | ||
marker: PhantomData<fn() -> (In, Out, Marker)>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be contravariant in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK you can still have subtyping between |
||
} | ||
|
||
pub struct IsExclusiveFunctionSystem; | ||
|
||
impl<Param, Marker, F> IntoSystem<(), (), (IsExclusiveFunctionSystem, Param, Marker)> for F | ||
impl<In, Out, Param, Marker, F> IntoSystem<In, Out, (IsExclusiveFunctionSystem, Param, Marker)> | ||
for F | ||
where | ||
In: 'static, | ||
Out: 'static, | ||
Param: ExclusiveSystemParam + 'static, | ||
Marker: 'static, | ||
F: ExclusiveSystemParamFunction<Param, Marker> + Send + Sync + 'static, | ||
F: ExclusiveSystemParamFunction<In, Out, Param, Marker> + Send + Sync + 'static, | ||
{ | ||
type System = ExclusiveFunctionSystem<Param, Marker, F>; | ||
type System = ExclusiveFunctionSystem<In, Out, Param, Marker, F>; | ||
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<Param, Marker, F> System for ExclusiveFunctionSystem<Param, Marker, F> | ||
impl<In, Out, Param, Marker, F> System for ExclusiveFunctionSystem<In, Out, Param, Marker, F> | ||
where | ||
In: 'static, | ||
Out: 'static, | ||
Param: ExclusiveSystemParam + 'static, | ||
Marker: 'static, | ||
F: ExclusiveSystemParamFunction<Param, Marker> + Send + Sync + 'static, | ||
F: ExclusiveSystemParamFunction<In, Out, Param, Marker> + Send + Sync + 'static, | ||
{ | ||
type In = (); | ||
type Out = (); | ||
type In = In; | ||
type Out = Out; | ||
|
||
#[inline] | ||
fn name(&self) -> Cow<'static, str> { | ||
|
@@ -90,20 +96,22 @@ 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; | ||
|
||
let params = <Param as ExclusiveSystemParam>::State::get_param( | ||
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<Param: ExclusiveSystemParam, Marker, T: ExclusiveSystemParamFunction<Param, Marker>> | ||
AsSystemLabel<(Param, Marker, IsExclusiveFunctionSystem)> for T | ||
impl<In, Out, Param, Marker, T> AsSystemLabel<(In, Out, Param, Marker, IsExclusiveFunctionSystem)> | ||
for T | ||
where | ||
Param: ExclusiveSystemParam, | ||
T: ExclusiveSystemParamFunction<In, Out, Param, Marker>, | ||
{ | ||
#[inline] | ||
fn as_system_label(&self) -> SystemLabelId { | ||
|
@@ -163,38 +174,70 @@ impl<Param: ExclusiveSystemParam, Marker, T: ExclusiveSystemParamFunction<Param, | |
/// | ||
/// This trait can be useful for making your own systems which accept other systems, | ||
/// sometimes called higher order systems. | ||
pub trait ExclusiveSystemParamFunction<Param: ExclusiveSystemParam, Marker>: | ||
pub trait ExclusiveSystemParamFunction<In, Out, Param: ExclusiveSystemParam, Marker>: | ||
Send + Sync + 'static | ||
{ | ||
fn run(&mut self, world: &mut World, param_value: ExclusiveSystemParamItem<Param>); | ||
fn run( | ||
&mut self, | ||
world: &mut World, | ||
input: In, | ||
param_value: ExclusiveSystemParamItem<Param>, | ||
) -> Out; | ||
} | ||
|
||
macro_rules! impl_exclusive_system_function { | ||
($($param: ident),*) => { | ||
#[allow(non_snake_case)] | ||
impl<Func: Send + Sync + 'static, $($param: ExclusiveSystemParam),*> ExclusiveSystemParamFunction<($($param,)*), ()> for Func | ||
impl<Out, Func: Send + Sync + 'static, $($param: ExclusiveSystemParam),*> 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<Out, $($param,)*>( | ||
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<Input, Out, Func: Send + Sync + 'static, $($param: ExclusiveSystemParam),*> ExclusiveSystemParamFunction<Input, Out, ($($param,)*), InputMarker> for Func | ||
where | ||
for <'a> &'a mut Func: | ||
FnMut(In<Input>, &mut World, $($param),*) -> Out + | ||
FnMut(In<Input>, &mut World, $(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<Input, Out, $($param,)*>( | ||
mut f: impl FnMut(In<Input>, &mut World, $($param,)*) -> Out, | ||
input: Input, | ||
world: &mut World, | ||
$($param: $param,)* | ||
) -> Out { | ||
f(In(input), world, $($param,)*) | ||
} | ||
let ($($param,)*) = param_value; | ||
call_inner(self, input, world, $($param),*) | ||
} | ||
} | ||
}; | ||
} | ||
// Note that we rely on the highest impl to be <= the highest order of the tuple impls | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that comment outdated now?