bevy_ecs/observer/
runner.rs1use core::any::Any;
4
5use crate::{
6    error::ErrorContext,
7    event::Event,
8    observer::TriggerContext,
9    prelude::*,
10    query::DebugCheckedUnwrap,
11    system::{ObserverSystem, RunSystemError},
12    world::DeferredWorld,
13};
14use bevy_ptr::PtrMut;
15
16pub type ObserverRunner =
23    unsafe fn(DeferredWorld, observer: Entity, &TriggerContext, event: PtrMut, trigger: PtrMut);
24
25pub(super) unsafe fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
36    mut world: DeferredWorld,
37    observer: Entity,
38    trigger_context: &TriggerContext,
39    event_ptr: PtrMut,
40    trigger_ptr: PtrMut,
41) {
42    let world = world.as_unsafe_world_cell();
43
44    let observer_cell = unsafe { world.get_entity(observer).debug_checked_unwrap() };
46    let mut state = unsafe { observer_cell.get_mut::<Observer>().debug_checked_unwrap() };
48
49    let last_trigger = world.last_trigger_id();
51    if state.last_trigger_id == last_trigger {
52        return;
53    }
54    state.last_trigger_id = last_trigger;
55
56    let trigger: &mut E::Trigger<'_> = unsafe { trigger_ptr.deref_mut() };
64
65    let on: On<E, B> = On::new(
66        unsafe { event_ptr.deref_mut() },
68        observer,
69        trigger,
70        trigger_context,
71    );
72
73    let system: *mut dyn ObserverSystem<E, B> = unsafe {
77        let system: &mut dyn Any = state.system.as_mut();
78        let system = system.downcast_mut::<S>().debug_checked_unwrap();
79        &mut *system
80    };
81
82    unsafe {
88        #[cfg(feature = "hotpatching")]
89        if world
90            .get_resource_ref::<crate::HotPatchChanges>()
91            .map(|r| {
92                r.last_changed()
93                    .is_newer_than((*system).get_last_run(), world.change_tick())
94            })
95            .unwrap_or(true)
96        {
97            (*system).refresh_hotpatch();
98        };
99
100        if let Err(RunSystemError::Failed(err)) = (*system)
101            .validate_param_unsafe(world)
102            .map_err(From::from)
103            .and_then(|()| (*system).run_unsafe(on, world))
104        {
105            let handler = state
106                .error_handler
107                .unwrap_or_else(|| world.default_error_handler());
108            handler(
109                err,
110                ErrorContext::Observer {
111                    name: (*system).name(),
112                    last_run: (*system).get_last_run(),
113                },
114            );
115        };
116        (*system).queue_deferred(world.into_deferred());
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use crate::{
124        error::{ignore, DefaultErrorHandler},
125        event::Event,
126        observer::On,
127    };
128
129    #[derive(Event)]
130    struct TriggerEvent;
131
132    #[test]
133    #[should_panic(expected = "I failed!")]
134    fn test_fallible_observer() {
135        fn system(_: On<TriggerEvent>) -> Result {
136            Err("I failed!".into())
137        }
138
139        let mut world = World::default();
140        world.add_observer(system);
141        Schedule::default().run(&mut world);
142        world.trigger(TriggerEvent);
143    }
144
145    #[test]
146    fn test_fallible_observer_ignored_errors() {
147        #[derive(Resource, Default)]
148        struct Ran(bool);
149
150        fn system(_: On<TriggerEvent>, mut ran: ResMut<Ran>) -> Result {
151            ran.0 = true;
152            Err("I failed!".into())
153        }
154
155        let mut world = World::default();
157        world.init_resource::<Ran>();
158        world.spawn(Observer::new(system).with_error_handler(ignore));
159        world.trigger(TriggerEvent);
160        assert!(world.resource::<Ran>().0);
161
162        let mut world = World::default();
164        world.init_resource::<Ran>();
165        world.spawn(Observer::new(system));
166        world.insert_resource(DefaultErrorHandler(ignore));
169        world.trigger(TriggerEvent);
170        assert!(world.resource::<Ran>().0);
171    }
172
173    #[test]
174    #[should_panic]
175    fn exclusive_system_cannot_be_observer() {
176        fn system(_: On<TriggerEvent>, _world: &mut World) {}
177        let mut world = World::default();
178        world.add_observer(system);
179    }
180}