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}