Allow observer systems to have outputs (#14159)
Fixes https://github.com/bevyengine/bevy/issues/14157 - Update the ObserverSystem traits to accept an `Out` parameter - Added a test where an observer system has a non-empty output which is piped into another system Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
d0583c8b54
commit
7f3fea9a5b
@ -8,31 +8,42 @@ use crate::{
|
|||||||
use super::IntoSystem;
|
use super::IntoSystem;
|
||||||
|
|
||||||
/// Implemented for systems that have an [`Observer`] as the first argument.
|
/// Implemented for systems that have an [`Observer`] as the first argument.
|
||||||
pub trait ObserverSystem<E: 'static, B: Bundle>:
|
///
|
||||||
System<In = Trigger<'static, E, B>, Out = ()> + Send + 'static
|
/// [`Observer`]: crate::observer::Observer
|
||||||
|
pub trait ObserverSystem<E: 'static, B: Bundle, Out = ()>:
|
||||||
|
System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: 'static, B: Bundle, T: System<In = Trigger<'static, E, B>, Out = ()> + Send + 'static>
|
impl<
|
||||||
ObserverSystem<E, B> for T
|
E: 'static,
|
||||||
|
B: Bundle,
|
||||||
|
Out,
|
||||||
|
T: System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static,
|
||||||
|
> ObserverSystem<E, B, Out> for T
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implemented for systems that convert into [`ObserverSystem`].
|
/// Implemented for systems that convert into [`ObserverSystem`].
|
||||||
pub trait IntoObserverSystem<E: 'static, B: Bundle, M>: Send + 'static {
|
pub trait IntoObserverSystem<E: 'static, B: Bundle, M, Out = ()>: Send + 'static {
|
||||||
/// The type of [`System`] that this instance converts into.
|
/// The type of [`System`] that this instance converts into.
|
||||||
type System: ObserverSystem<E, B>;
|
type System: ObserverSystem<E, B, Out>;
|
||||||
|
|
||||||
/// Turns this value into its corresponding [`System`].
|
/// Turns this value into its corresponding [`System`].
|
||||||
fn into_system(this: Self) -> Self::System;
|
fn into_system(this: Self) -> Self::System;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: IntoSystem<Trigger<'static, E, B>, (), M> + Send + 'static, M, E: 'static, B: Bundle>
|
impl<
|
||||||
IntoObserverSystem<E, B, M> for S
|
S: IntoSystem<Trigger<'static, E, B>, Out, M> + Send + 'static,
|
||||||
|
M,
|
||||||
|
Out,
|
||||||
|
E: 'static,
|
||||||
|
B: Bundle,
|
||||||
|
> IntoObserverSystem<E, B, M, Out> for S
|
||||||
where
|
where
|
||||||
S::System: ObserverSystem<E, B>,
|
S::System: ObserverSystem<E, B, Out>,
|
||||||
{
|
{
|
||||||
type System = <S as IntoSystem<Trigger<'static, E, B>, (), M>>::System;
|
type System = <S as IntoSystem<Trigger<'static, E, B>, Out, M>>::System;
|
||||||
|
|
||||||
fn into_system(this: Self) -> Self::System {
|
fn into_system(this: Self) -> Self::System {
|
||||||
IntoSystem::into_system(this)
|
IntoSystem::into_system(this)
|
||||||
@ -42,23 +53,23 @@ where
|
|||||||
macro_rules! impl_system_function {
|
macro_rules! impl_system_function {
|
||||||
($($param: ident),*) => {
|
($($param: ident),*) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl<E: 'static, B: Bundle, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn(Trigger<E, B>, $($param,)*)> for Func
|
impl<E: 'static, B: Bundle, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn(Trigger<E, B>, $($param,)*)> for Func
|
||||||
where
|
where
|
||||||
for <'a> &'a mut Func:
|
for <'a> &'a mut Func:
|
||||||
FnMut(Trigger<E, B>, $($param),*) +
|
FnMut(Trigger<E, B>, $($param),*) -> Out +
|
||||||
FnMut(Trigger<E, B>, $(SystemParamItem<$param>),*)
|
FnMut(Trigger<E, B>, $(SystemParamItem<$param>),*) -> Out, Out: 'static
|
||||||
{
|
{
|
||||||
type In = Trigger<'static, E, B>;
|
type In = Trigger<'static, E, B>;
|
||||||
type Out = ();
|
type Out = Out;
|
||||||
type Param = ($($param,)*);
|
type Param = ($($param,)*);
|
||||||
#[inline]
|
#[inline]
|
||||||
fn run(&mut self, input: Trigger<'static, E, B>, param_value: SystemParamItem< ($($param,)*)>) {
|
fn run(&mut self, input: Trigger<'static, E, B>, param_value: SystemParamItem< ($($param,)*)>) -> Out {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn call_inner<E: 'static, B: Bundle, $($param,)*>(
|
fn call_inner<E: 'static, B: Bundle, Out, $($param,)*>(
|
||||||
mut f: impl FnMut(Trigger<'static, E, B>, $($param,)*),
|
mut f: impl FnMut(Trigger<'static, E, B>, $($param,)*) -> Out,
|
||||||
input: Trigger<'static, E, B>,
|
input: Trigger<'static, E, B>,
|
||||||
$($param: $param,)*
|
$($param: $param,)*
|
||||||
){
|
) -> Out{
|
||||||
f(input, $($param,)*)
|
f(input, $($param,)*)
|
||||||
}
|
}
|
||||||
let ($($param,)*) = param_value;
|
let ($($param,)*) = param_value;
|
||||||
@ -69,3 +80,37 @@ macro_rules! impl_system_function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
all_tuples!(impl_system_function, 0, 16, F);
|
all_tuples!(impl_system_function, 0, 16, F);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
self as bevy_ecs,
|
||||||
|
event::Event,
|
||||||
|
observer::Trigger,
|
||||||
|
system::{In, IntoSystem},
|
||||||
|
world::World,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Event)]
|
||||||
|
struct TriggerEvent;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_piped_observer_systems_no_input() {
|
||||||
|
fn a(_: Trigger<TriggerEvent>) {}
|
||||||
|
fn b() {}
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.observe(a.pipe(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_piped_observer_systems_with_inputs() {
|
||||||
|
fn a(_: Trigger<TriggerEvent>) -> u32 {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
fn b(_: In<u32>) {}
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.observe(a.pipe(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user