bevy_ecs/system/
observer_system.rs

1use alloc::{borrow::Cow, vec::Vec};
2use core::marker::PhantomData;
3
4use crate::{
5    archetype::ArchetypeComponentId,
6    component::{ComponentId, Tick},
7    error::Result,
8    never::Never,
9    prelude::{Bundle, Trigger},
10    query::Access,
11    schedule::{Fallible, Infallible},
12    system::{input::SystemIn, System},
13    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
14};
15
16use super::{IntoSystem, SystemParamValidationError};
17
18/// Implemented for [`System`]s that have a [`Trigger`] as the first argument.
19pub trait ObserverSystem<E: 'static, B: Bundle, Out = Result>:
20    System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static
21{
22}
23
24impl<E: 'static, B: Bundle, Out, T> ObserverSystem<E, B, Out> for T where
25    T: System<In = Trigger<'static, E, B>, Out = Out> + Send + 'static
26{
27}
28
29/// Implemented for systems that convert into [`ObserverSystem`].
30///
31/// # Usage notes
32///
33/// This trait should only be used as a bound for trait implementations or as an
34/// argument to a function. If an observer system needs to be returned from a
35/// function or stored somewhere, use [`ObserverSystem`] instead of this trait.
36#[diagnostic::on_unimplemented(
37    message = "`{Self}` cannot become an `ObserverSystem`",
38    label = "the trait `IntoObserverSystem` is not implemented",
39    note = "for function `ObserverSystem`s, ensure the first argument is a `Trigger<T>` and any subsequent ones are `SystemParam`"
40)]
41pub trait IntoObserverSystem<E: 'static, B: Bundle, M, Out = Result>: Send + 'static {
42    /// The type of [`System`] that this instance converts into.
43    type System: ObserverSystem<E, B, Out>;
44
45    /// Turns this value into its corresponding [`System`].
46    fn into_system(this: Self) -> Self::System;
47}
48
49impl<E, B, M, S, Out> IntoObserverSystem<E, B, (Fallible, M), Out> for S
50where
51    S: IntoSystem<Trigger<'static, E, B>, Out, M> + Send + 'static,
52    S::System: ObserverSystem<E, B, Out>,
53    E: 'static,
54    B: Bundle,
55{
56    type System = S::System;
57
58    fn into_system(this: Self) -> Self::System {
59        IntoSystem::into_system(this)
60    }
61}
62
63impl<E, B, M, S> IntoObserverSystem<E, B, (Infallible, M), Result> for S
64where
65    S: IntoSystem<Trigger<'static, E, B>, (), M> + Send + 'static,
66    S::System: ObserverSystem<E, B, ()>,
67    E: Send + Sync + 'static,
68    B: Bundle,
69{
70    type System = InfallibleObserverWrapper<E, B, S::System, ()>;
71
72    fn into_system(this: Self) -> Self::System {
73        InfallibleObserverWrapper::new(IntoSystem::into_system(this))
74    }
75}
76impl<E, B, M, S> IntoObserverSystem<E, B, (Never, M), Result> for S
77where
78    S: IntoSystem<Trigger<'static, E, B>, Never, M> + Send + 'static,
79    E: Send + Sync + 'static,
80    B: Bundle,
81{
82    type System = InfallibleObserverWrapper<E, B, S::System, Never>;
83
84    fn into_system(this: Self) -> Self::System {
85        InfallibleObserverWrapper::new(IntoSystem::into_system(this))
86    }
87}
88
89/// A wrapper that converts an observer system that returns `()` into one that returns `Ok(())`.
90pub struct InfallibleObserverWrapper<E, B, S, Out> {
91    observer: S,
92    _marker: PhantomData<(E, B, Out)>,
93}
94
95impl<E, B, S, Out> InfallibleObserverWrapper<E, B, S, Out> {
96    /// Create a new `InfallibleObserverWrapper`.
97    pub fn new(observer: S) -> Self {
98        Self {
99            observer,
100            _marker: PhantomData,
101        }
102    }
103}
104
105impl<E, B, S, Out> System for InfallibleObserverWrapper<E, B, S, Out>
106where
107    S: ObserverSystem<E, B, Out>,
108    E: Send + Sync + 'static,
109    B: Bundle,
110    Out: Send + Sync + 'static,
111{
112    type In = Trigger<'static, E, B>;
113    type Out = Result;
114
115    #[inline]
116    fn name(&self) -> Cow<'static, str> {
117        self.observer.name()
118    }
119
120    #[inline]
121    fn component_access(&self) -> &Access<ComponentId> {
122        self.observer.component_access()
123    }
124
125    #[inline]
126    fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
127        self.observer.archetype_component_access()
128    }
129
130    #[inline]
131    fn is_send(&self) -> bool {
132        self.observer.is_send()
133    }
134
135    #[inline]
136    fn is_exclusive(&self) -> bool {
137        self.observer.is_exclusive()
138    }
139
140    #[inline]
141    fn has_deferred(&self) -> bool {
142        self.observer.has_deferred()
143    }
144
145    #[inline]
146    unsafe fn run_unsafe(
147        &mut self,
148        input: SystemIn<'_, Self>,
149        world: UnsafeWorldCell,
150    ) -> Self::Out {
151        self.observer.run_unsafe(input, world);
152        Ok(())
153    }
154
155    #[inline]
156    fn apply_deferred(&mut self, world: &mut World) {
157        self.observer.apply_deferred(world);
158    }
159
160    #[inline]
161    fn queue_deferred(&mut self, world: DeferredWorld) {
162        self.observer.queue_deferred(world);
163    }
164
165    #[inline]
166    unsafe fn validate_param_unsafe(
167        &mut self,
168        world: UnsafeWorldCell,
169    ) -> Result<(), SystemParamValidationError> {
170        self.observer.validate_param_unsafe(world)
171    }
172
173    #[inline]
174    fn initialize(&mut self, world: &mut World) {
175        self.observer.initialize(world);
176    }
177
178    #[inline]
179    fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
180        self.observer.update_archetype_component_access(world);
181    }
182
183    #[inline]
184    fn check_change_tick(&mut self, change_tick: Tick) {
185        self.observer.check_change_tick(change_tick);
186    }
187
188    #[inline]
189    fn get_last_run(&self) -> Tick {
190        self.observer.get_last_run()
191    }
192
193    #[inline]
194    fn set_last_run(&mut self, last_run: Tick) {
195        self.observer.set_last_run(last_run);
196    }
197
198    fn default_system_sets(&self) -> Vec<crate::schedule::InternedSystemSet> {
199        self.observer.default_system_sets()
200    }
201}
202
203#[cfg(test)]
204mod tests {
205    use crate::{
206        event::Event,
207        observer::Trigger,
208        system::{In, IntoSystem},
209        world::World,
210    };
211
212    #[derive(Event)]
213    struct TriggerEvent;
214
215    #[test]
216    fn test_piped_observer_systems_no_input() {
217        fn a(_: Trigger<TriggerEvent>) {}
218        fn b() {}
219
220        let mut world = World::new();
221        world.add_observer(a.pipe(b));
222    }
223
224    #[test]
225    fn test_piped_observer_systems_with_inputs() {
226        fn a(_: Trigger<TriggerEvent>) -> u32 {
227            3
228        }
229        fn b(_: In<u32>) {}
230
231        let mut world = World::new();
232        world.add_observer(a.pipe(b));
233    }
234}