bevy_ecs/event/
trigger.rs

1use crate::{
2    component::ComponentId,
3    entity::Entity,
4    event::{EntityEvent, Event},
5    observer::{CachedObservers, TriggerContext},
6    traversal::Traversal,
7    world::DeferredWorld,
8};
9use bevy_ptr::PtrMut;
10use core::{fmt, marker::PhantomData};
11
12/// [`Trigger`] determines _how_ an [`Event`] is triggered when [`World::trigger`](crate::world::World::trigger) is called.
13/// This decides which [`Observer`](crate::observer::Observer)s will run, what data gets passed to them, and the order they will
14/// be executed in.
15///
16/// Implementing [`Trigger`] is "advanced-level" territory, and is generally unnecessary unless you are developing highly specialized
17/// [`Event`] trigger logic.
18///
19/// Bevy comes with a number of built-in [`Trigger`] implementations (see their documentation for more info):
20/// - [`GlobalTrigger`]: The [`Event`] derive defaults to using this
21/// - [`EntityTrigger`]: The [`EntityEvent`] derive defaults to using this
22/// - [`PropagateEntityTrigger`]: The [`EntityEvent`] derive uses this when propagation is enabled.
23/// - [`EntityComponentsTrigger`]: Used by Bevy's [component lifecycle events](crate::lifecycle).
24///
25/// # Safety
26///
27/// Implementing this properly is _advanced_ soundness territory! Implementers must abide by the following:
28///
29/// - The `E`' [`Event::Trigger`] must be constrained to the implemented [`Trigger`] type, as part of the implementation.
30///   This prevents other [`Trigger`] implementations from directly deferring to your implementation, which is a very easy
31///   soundness misstep, as most [`Trigger`] implementations will invoke observers that are developed _for their specific [`Trigger`] type_.
32///   Without this constraint, something like [`GlobalTrigger`] could be called for _any_ [`Event`] type, even one that expects a different
33///   [`Trigger`] type. This would result in an unsound cast of [`GlobalTrigger`] reference.
34///   This is not expressed as an explicit type constraint,, as the `for<'a> Event::Trigger<'a>` lifetime can mismatch explicit lifetimes in
35///   some impls.
36pub unsafe trait Trigger<E: Event> {
37    /// Trigger the given `event`, running every [`Observer`](crate::observer::Observer) that matches the `event`, as defined by this
38    /// [`Trigger`] and the state stored on `self`.
39    ///
40    /// # Safety
41    /// - The [`CachedObservers`] `observers` must come from the [`DeferredWorld`] `world`
42    /// - [`TriggerContext`] must contain an [`EventKey`](crate::event::EventKey) that matches the `E` [`Event`] type
43    /// - `observers` must correspond to observers compatible with the event type `E`
44    /// - Read and abide by the "Safety" section defined in the top-level [`Trigger`] docs. Calling this function is
45    ///   unintuitively risky. _Do not use it directly unless you know what you are doing_. Importantly, this should only
46    ///   be called for an `event` whose [`Event::Trigger`] matches this trigger.
47    unsafe fn trigger(
48        &mut self,
49        world: DeferredWorld,
50        observers: &CachedObservers,
51        trigger_context: &TriggerContext,
52        event: &mut E,
53    );
54}
55
56/// A [`Trigger`] that runs _every_ "global" [`Observer`](crate::observer::Observer) (ex: registered via [`World::add_observer`](crate::world::World::add_observer))
57/// that matches the given [`Event`].
58///
59/// The [`Event`] derive defaults to using this [`Trigger`], and it is usable for any [`Event`] type.
60#[derive(Default, Debug)]
61pub struct GlobalTrigger;
62
63// SAFETY:
64// - `E`'s [`Event::Trigger`] is constrained to [`GlobalTrigger`]
65// - The implementation abides by the other safety constraints defined in [`Trigger`]
66unsafe impl<E: for<'a> Event<Trigger<'a> = Self>> Trigger<E> for GlobalTrigger {
67    unsafe fn trigger(
68        &mut self,
69        world: DeferredWorld,
70        observers: &CachedObservers,
71        trigger_context: &TriggerContext,
72        event: &mut E,
73    ) {
74        // SAFETY:
75        // - The caller of `trigger` ensures that `observers` come from the `world`
76        // - The passed in event ptr comes from `event`, which is E: Event
77        // - E: Event::Trigger is constrained to GlobalTrigger
78        // - The caller of `trigger` ensures that `TriggerContext::event_key` matches `event`
79        unsafe {
80            self.trigger_internal(world, observers, trigger_context, event.into());
81        }
82    }
83}
84
85impl GlobalTrigger {
86    /// # Safety
87    /// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type
88    /// - `event` must point to an [`Event`]
89    /// -  The `event` [`Event::Trigger`] must be [`GlobalTrigger`]
90    /// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
91    unsafe fn trigger_internal(
92        &mut self,
93        mut world: DeferredWorld,
94        observers: &CachedObservers,
95        trigger_context: &TriggerContext,
96        mut event: PtrMut,
97    ) {
98        // SAFETY: `observers` is the only active reference to something in `world`
99        unsafe {
100            world.as_unsafe_world_cell().increment_trigger_id();
101        }
102        for (observer, runner) in observers.global_observers() {
103            // SAFETY:
104            // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
105            // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
106            // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `event`, enforced by `trigger_internal`
107            // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
108            // - this abides by the nuances defined in the `Trigger` safety docs
109            unsafe {
110                (runner)(
111                    world.reborrow(),
112                    *observer,
113                    trigger_context,
114                    event.reborrow(),
115                    self.into(),
116                );
117            }
118        }
119    }
120}
121
122/// An [`EntityEvent`] [`Trigger`] that does two things:
123/// - Runs all "global" [`Observer`] (ex: registered via [`World::add_observer`](crate::world::World::add_observer))
124///   that matches the given [`Event`]. This is the same behavior as [`GlobalTrigger`].
125/// - Runs every "entity scoped" [`Observer`] that watches the given [`EntityEvent::event_target`] entity.
126///
127/// The [`EntityEvent`] derive defaults to using this [`Trigger`], and it is usable for any [`EntityEvent`] type.
128///
129/// [`Observer`]: crate::observer::Observer
130#[derive(Default, Debug)]
131pub struct EntityTrigger;
132
133// SAFETY:
134// - `E`'s [`Event::Trigger`] is constrained to [`EntityTrigger`]
135// - The implementation abides by the other safety constraints defined in [`Trigger`]
136unsafe impl<E: EntityEvent + for<'a> Event<Trigger<'a> = Self>> Trigger<E> for EntityTrigger {
137    unsafe fn trigger(
138        &mut self,
139        world: DeferredWorld,
140        observers: &CachedObservers,
141        trigger_context: &TriggerContext,
142        event: &mut E,
143    ) {
144        let entity = event.event_target();
145        // SAFETY:
146        // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
147        // - the passed in event pointer comes from `event`, which is an `Event`
148        // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
149        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
150        unsafe {
151            trigger_entity_internal(
152                world,
153                observers,
154                event.into(),
155                self.into(),
156                entity,
157                trigger_context,
158            );
159        }
160    }
161}
162
163/// Trigger observers watching for the given entity event.
164/// The `target_entity` should match the [`EntityEvent::event_target`] on `event` for logical correctness.
165///
166/// # Safety
167/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type
168/// - `event` must point to an [`Event`]
169/// - `trigger` must correspond to the [`Event::Trigger`] type expected by the `event`
170/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
171/// - Read, understand, and abide by the [`Trigger`] safety documentation
172// Note: this is not an EntityTrigger method because we want to reuse this logic for the entity propagation trigger
173#[inline(never)]
174pub unsafe fn trigger_entity_internal(
175    mut world: DeferredWorld,
176    observers: &CachedObservers,
177    mut event: PtrMut,
178    mut trigger: PtrMut,
179    target_entity: Entity,
180    trigger_context: &TriggerContext,
181) {
182    // SAFETY: there are no outstanding world references
183    unsafe {
184        world.as_unsafe_world_cell().increment_trigger_id();
185    }
186    for (observer, runner) in observers.global_observers() {
187        // SAFETY:
188        // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`
189        // - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`
190        // - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`
191        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`
192        unsafe {
193            (runner)(
194                world.reborrow(),
195                *observer,
196                trigger_context,
197                event.reborrow(),
198                trigger.reborrow(),
199            );
200        }
201    }
202
203    if let Some(map) = observers.entity_observers().get(&target_entity) {
204        for (observer, runner) in map {
205            // SAFETY:
206            // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`
207            // - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`
208            // - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`
209            // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`
210            unsafe {
211                (runner)(
212                    world.reborrow(),
213                    *observer,
214                    trigger_context,
215                    event.reborrow(),
216                    trigger.reborrow(),
217                );
218            }
219        }
220    }
221}
222
223/// An [`EntityEvent`] [`Trigger`] that behaves like [`EntityTrigger`], but "propagates" the event
224/// using an [`Entity`] [`Traversal`]. At each step in the propagation, the [`EntityTrigger`] logic will
225/// be run, until [`PropagateEntityTrigger::propagate`] is false, or there are no entities left to traverse.
226///
227/// This is used by the [`EntityEvent`] derive when `#[entity_event(propagate)]` is enabled. It is usable by every
228/// [`EntityEvent`] type.
229///
230/// If `AUTO_PROPAGATE` is `true`, [`PropagateEntityTrigger::propagate`] will default to `true`.
231pub struct PropagateEntityTrigger<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> {
232    /// The original [`Entity`] the [`Event`] was _first_ triggered for.
233    pub original_event_target: Entity,
234
235    /// Whether or not to continue propagating using the `T` [`Traversal`]. If this is false,
236    /// The [`Traversal`] will stop on the current entity.
237    pub propagate: bool,
238
239    _marker: PhantomData<(E, T)>,
240}
241
242impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> Default
243    for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
244{
245    fn default() -> Self {
246        Self {
247            original_event_target: Entity::PLACEHOLDER,
248            propagate: AUTO_PROPAGATE,
249            _marker: Default::default(),
250        }
251    }
252}
253
254impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> fmt::Debug
255    for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
256{
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        f.debug_struct("PropagateEntityTrigger")
259            .field("original_event_target", &self.original_event_target)
260            .field("propagate", &self.propagate)
261            .field("_marker", &self._marker)
262            .finish()
263    }
264}
265
266// SAFETY:
267// - `E`'s [`Event::Trigger`] is constrained to [`PropagateEntityTrigger<E>`]
268unsafe impl<
269        const AUTO_PROPAGATE: bool,
270        E: EntityEvent + for<'a> Event<Trigger<'a> = Self>,
271        T: Traversal<E>,
272    > Trigger<E> for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>
273{
274    unsafe fn trigger(
275        &mut self,
276        mut world: DeferredWorld,
277        observers: &CachedObservers,
278        trigger_context: &TriggerContext,
279        event: &mut E,
280    ) {
281        let mut current_entity = event.event_target();
282        self.original_event_target = current_entity;
283        // SAFETY:
284        // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
285        // - the passed in event pointer comes from `event`, which is an `Event`
286        // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
287        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
288        unsafe {
289            trigger_entity_internal(
290                world.reborrow(),
291                observers,
292                event.into(),
293                self.into(),
294                current_entity,
295                trigger_context,
296            );
297        }
298
299        loop {
300            if !self.propagate {
301                return;
302            }
303            if let Ok(entity) = world.get_entity(current_entity)
304                && let Some(item) = entity.get_components::<T>()
305                && let Some(traverse_to) = T::traverse(item, event)
306            {
307                current_entity = traverse_to;
308            } else {
309                break;
310            }
311
312            *event.event_target_mut() = current_entity;
313            // SAFETY:
314            // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
315            // - the passed in event pointer comes from `event`, which is an `Event`
316            // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
317            // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
318            unsafe {
319                trigger_entity_internal(
320                    world.reborrow(),
321                    observers,
322                    event.into(),
323                    self.into(),
324                    current_entity,
325                    trigger_context,
326                );
327            }
328        }
329    }
330}
331
332/// An [`EntityEvent`] [`Trigger`] that, in addition to behaving like a normal [`EntityTrigger`], _also_ runs observers
333/// that watch for components that match the slice of [`ComponentId`]s referenced in [`EntityComponentsTrigger`]. This includes
334/// both _global_ observers of those components and "entity scoped" observers that watch the [`EntityEvent::event_target`].
335///
336/// This is used by Bevy's built-in [lifecycle events](crate::lifecycle).
337#[derive(Default)]
338pub struct EntityComponentsTrigger<'a> {
339    /// All of the components whose observers were triggered together for the target entity. For example,
340    /// if components `A` and `B` are added together, producing the [`Add`](crate::lifecycle::Add) event, this will
341    /// contain the [`ComponentId`] for both `A` and `B`.
342    pub components: &'a [ComponentId],
343}
344
345// SAFETY:
346// - `E`'s [`Event::Trigger`] is constrained to [`EntityComponentsTrigger`]
347unsafe impl<'a, E: EntityEvent + Event<Trigger<'a> = EntityComponentsTrigger<'a>>> Trigger<E>
348    for EntityComponentsTrigger<'a>
349{
350    unsafe fn trigger(
351        &mut self,
352        world: DeferredWorld,
353        observers: &CachedObservers,
354        trigger_context: &TriggerContext,
355        event: &mut E,
356    ) {
357        let entity = event.event_target();
358        // SAFETY:
359        // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
360        // - the passed in event pointer comes from `event`, which is an `Event`
361        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
362        unsafe {
363            self.trigger_internal(world, observers, event.into(), entity, trigger_context);
364        }
365    }
366}
367
368impl<'a> EntityComponentsTrigger<'a> {
369    /// # Safety
370    /// - `observers` must come from the `world` [`DeferredWorld`]
371    /// - `event` must point to an [`Event`] whose [`Event::Trigger`] is [`EntityComponentsTrigger`]
372    /// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.
373    #[inline(never)]
374    unsafe fn trigger_internal(
375        &mut self,
376        mut world: DeferredWorld,
377        observers: &CachedObservers,
378        mut event: PtrMut,
379        entity: Entity,
380        trigger_context: &TriggerContext,
381    ) {
382        // SAFETY:
383        // - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
384        // - the passed in event pointer comes from `event`, which is an `Event`
385        // - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`
386        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`
387        unsafe {
388            trigger_entity_internal(
389                world.reborrow(),
390                observers,
391                event.reborrow(),
392                self.into(),
393                entity,
394                trigger_context,
395            );
396        }
397
398        // Trigger observers watching for a specific component
399        for id in self.components {
400            if let Some(component_observers) = observers.component_observers().get(id) {
401                for (observer, runner) in component_observers.global_observers() {
402                    // SAFETY:
403                    // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
404                    // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
405                    // - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`
406                    // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
407                    unsafe {
408                        (runner)(
409                            world.reborrow(),
410                            *observer,
411                            trigger_context,
412                            event.reborrow(),
413                            self.into(),
414                        );
415                    }
416                }
417
418                if let Some(map) = component_observers
419                    .entity_component_observers()
420                    .get(&entity)
421                {
422                    for (observer, runner) in map {
423                        // SAFETY:
424                        // - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`
425                        // - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`
426                        // - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`
427                        // - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`
428                        unsafe {
429                            (runner)(
430                                world.reborrow(),
431                                *observer,
432                                trigger_context,
433                                event.reborrow(),
434                                self.into(),
435                            );
436                        }
437                    }
438                }
439            }
440        }
441    }
442}