bevy_ecs/event/
trigger.rs

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