1use bevy_utils::all_tuples;
2
3use crate::{
4 prelude::{Bundle, Trigger},
5 system::{System, SystemParam, SystemParamFunction, SystemParamItem},
6};
7
8use super::IntoSystem;
9
10pub trait ObserverSystem<E: 'static, B: Bundle, Out = ()>:
14 System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static
15{
16}
17
18impl<
19 E: 'static,
20 B: Bundle,
21 Out,
22 T: System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static,
23 > ObserverSystem<E, B, Out> for T
24{
25}
26
27pub trait IntoObserverSystem<E: 'static, B: Bundle, M, Out = ()>: Send + 'static {
29 type System: ObserverSystem<E, B, Out>;
31
32 fn into_system(this: Self) -> Self::System;
34}
35
36impl<
37 S: IntoSystem<Trigger<'static, E, B>, Out, M> + Send + 'static,
38 M,
39 Out,
40 E: 'static,
41 B: Bundle,
42 > IntoObserverSystem<E, B, M, Out> for S
43where
44 S::System: ObserverSystem<E, B, Out>,
45{
46 type System = <S as IntoSystem<Trigger<'static, E, B>, Out, M>>::System;
47
48 fn into_system(this: Self) -> Self::System {
49 IntoSystem::into_system(this)
50 }
51}
52
53macro_rules! impl_system_function {
54 ($($param: ident),*) => {
55 #[allow(non_snake_case)]
56 impl<E: 'static, B: Bundle, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn(Trigger<E, B>, $($param,)*)> for Func
57 where
58 for <'a> &'a mut Func:
59 FnMut(Trigger<E, B>, $($param),*) -> Out +
60 FnMut(Trigger<E, B>, $(SystemParamItem<$param>),*) -> Out, Out: 'static
61 {
62 type In = Trigger<'static, E, B>;
63 type Out = Out;
64 type Param = ($($param,)*);
65 #[inline]
66 fn run(&mut self, input: Trigger<'static, E, B>, param_value: SystemParamItem< ($($param,)*)>) -> Out {
67 #[allow(clippy::too_many_arguments)]
68 fn call_inner<E: 'static, B: Bundle, Out, $($param,)*>(
69 mut f: impl FnMut(Trigger<'static, E, B>, $($param,)*) -> Out,
70 input: Trigger<'static, E, B>,
71 $($param: $param,)*
72 ) -> Out{
73 f(input, $($param,)*)
74 }
75 let ($($param,)*) = param_value;
76 call_inner(self, input, $($param),*)
77 }
78 }
79 }
80}
81
82all_tuples!(impl_system_function, 0, 16, F);
83
84#[cfg(test)]
85mod tests {
86 use crate::{
87 self as bevy_ecs,
88 event::Event,
89 observer::Trigger,
90 system::{In, IntoSystem},
91 world::World,
92 };
93
94 #[derive(Event)]
95 struct TriggerEvent;
96
97 #[test]
98 fn test_piped_observer_systems_no_input() {
99 fn a(_: Trigger<TriggerEvent>) {}
100 fn b() {}
101
102 let mut world = World::new();
103 world.observe(a.pipe(b));
104 }
105
106 #[test]
107 fn test_piped_observer_systems_with_inputs() {
108 fn a(_: Trigger<TriggerEvent>) -> u32 {
109 3
110 }
111 fn b(_: In<u32>) {}
112
113 let mut world = World::new();
114 world.observe(a.pipe(b));
115 }
116}