Skip to main content

bevy_ecs/world/
deferred_world.rs

1use core::ops::Deref;
2
3use bevy_utils::prelude::DebugName;
4
5use crate::{
6    archetype::Archetype,
7    change_detection::{MaybeLocation, MutUntyped, Tick},
8    component::{ComponentId, Mutable},
9    entity::Entity,
10    event::{EntityComponentsTrigger, Event, EventKey, Trigger},
11    lifecycle::{DiscardEvent, HookContext, InsertEvent, DISCARD, INSERT},
12    message::{Message, MessageId, Messages, WriteBatchIds},
13    observer::TriggerContext,
14    prelude::{Component, QueryState},
15    query::{QueryData, QueryFilter},
16    relationship::RelationshipHookMode,
17    resource::Resource,
18    system::{Commands, Query},
19    world::{error::EntityMutableFetchError, EntityFetcher, WorldEntityFetch},
20};
21
22use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World};
23
24/// A [`World`] reference that disallows structural ECS changes.
25/// This includes initializing resources, registering components or spawning entities.
26///
27/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.
28pub struct DeferredWorld<'w> {
29    // SAFETY: Implementers must not use this reference to make structural changes
30    world: UnsafeWorldCell<'w>,
31}
32
33impl<'w> Deref for DeferredWorld<'w> {
34    type Target = World;
35
36    fn deref(&self) -> &Self::Target {
37        // SAFETY: Structural changes cannot be made through &World
38        unsafe { self.world.world() }
39    }
40}
41
42impl<'w> UnsafeWorldCell<'w> {
43    /// Turn self into a [`DeferredWorld`]
44    ///
45    /// # Safety
46    /// Caller must ensure there are no outstanding mutable references to world and no
47    /// outstanding references to the world's command queue, resource or component data
48    #[inline]
49    pub unsafe fn into_deferred(self) -> DeferredWorld<'w> {
50        DeferredWorld { world: self }
51    }
52}
53
54impl<'w> From<&'w mut World> for DeferredWorld<'w> {
55    fn from(world: &'w mut World) -> DeferredWorld<'w> {
56        DeferredWorld {
57            world: world.as_unsafe_world_cell(),
58        }
59    }
60}
61
62impl<'w> From<&'w mut DeferredWorld<'_>> for DeferredWorld<'w> {
63    fn from(world: &'w mut DeferredWorld<'_>) -> DeferredWorld<'w> {
64        world.reborrow()
65    }
66}
67
68impl<'w> DeferredWorld<'w> {
69    /// Reborrow self as a new instance of [`DeferredWorld`]
70    #[inline]
71    pub fn reborrow(&mut self) -> DeferredWorld<'_> {
72        DeferredWorld { world: self.world }
73    }
74
75    /// Creates a [`Commands`] instance that pushes to the world's command queue
76    #[inline]
77    pub fn commands(&mut self) -> Commands<'_, '_> {
78        // SAFETY: &mut self ensure that there are no outstanding accesses to the queue
79        unsafe { self.world.commands() }
80    }
81
82    /// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.
83    /// Returns `None` if the `entity` does not have a [`Component`] of the given type.
84    #[inline]
85    pub fn get_mut<T: Component<Mutability = Mutable>>(
86        &mut self,
87        entity: Entity,
88    ) -> Option<Mut<'_, T>> {
89        self.get_entity_mut(entity).ok()?.into_mut()
90    }
91
92    /// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and
93    /// runs the provided closure on it, returning the result if `T` was available.
94    /// This will trigger the `Remove` and `Discard` component hooks without
95    /// causing an archetype move.
96    ///
97    /// This is most useful with immutable components, where removal and reinsertion
98    /// is the only way to modify a value.
99    ///
100    /// If you do not need to ensure the above hooks are triggered, and your component
101    /// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).
102    #[inline]
103    #[track_caller]
104    pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(
105        &mut self,
106        entity: Entity,
107        relationship_hook_mode: RelationshipHookMode,
108        f: impl FnOnce(&mut T) -> R,
109    ) -> Result<Option<R>, EntityMutableFetchError> {
110        // If the component is not registered, then it doesn't exist on this entity, so no action required.
111        let Some(component_id) = self.component_id::<T>() else {
112            return Ok(None);
113        };
114
115        self.modify_component_by_id_with_relationship_hook_mode(
116            entity,
117            component_id,
118            relationship_hook_mode,
119            move |component| {
120                // SAFETY: component matches the component_id collected in the above line
121                let mut component = unsafe { component.with_type::<T>() };
122
123                f(&mut component)
124            },
125        )
126    }
127
128    /// Temporarily removes a [`Component`] identified by the provided
129    /// [`ComponentId`] from the provided [`Entity`] and runs the provided
130    /// closure on it, returning the result if the component was available.
131    /// This will trigger the `Remove` and `Discard` component hooks without
132    /// causing an archetype move.
133    ///
134    /// This is most useful with immutable components, where removal and reinsertion
135    /// is the only way to modify a value.
136    ///
137    /// If you do not need to ensure the above hooks are triggered, and your component
138    /// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).
139    ///
140    /// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)
141    /// whenever possible.
142    #[inline]
143    #[track_caller]
144    pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(
145        &mut self,
146        entity: Entity,
147        component_id: ComponentId,
148        relationship_hook_mode: RelationshipHookMode,
149        f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,
150    ) -> Result<Option<R>, EntityMutableFetchError> {
151        let entity_cell = self.get_entity_mut(entity)?;
152
153        if !entity_cell.contains_id(component_id) {
154            return Ok(None);
155        }
156
157        let archetype = &raw const *entity_cell.archetype();
158
159        // SAFETY:
160        // - DeferredWorld ensures archetype pointer will remain valid as no
161        //   relocations will occur.
162        // - component_id exists on this world and this entity
163        // - DISCARD is able to accept ZST events
164        unsafe {
165            let archetype = &*archetype;
166            self.trigger_on_discard(
167                archetype,
168                entity,
169                [component_id].into_iter(),
170                MaybeLocation::caller(),
171                relationship_hook_mode,
172            );
173            if archetype.has_discard_observer() {
174                // SAFETY: the DISCARD event_key corresponds to the Discard event's type
175                self.trigger_raw(
176                    DISCARD,
177                    &mut DiscardEvent { entity },
178                    &mut EntityComponentsTrigger {
179                        components: &[component_id],
180                        old_archetype: Some(archetype),
181                        new_archetype: Some(archetype),
182                    },
183                    MaybeLocation::caller(),
184                );
185            }
186        }
187
188        let mut entity_cell = self
189            .get_entity_mut(entity)
190            .expect("entity access confirmed above");
191
192        // SAFETY: we will run the required hooks to simulate removal/replacement.
193        let mut component = unsafe {
194            entity_cell
195                .get_mut_assume_mutable_by_id(component_id)
196                .expect("component access confirmed above")
197        };
198
199        let result = f(component.reborrow());
200
201        // Simulate adding this component by updating the relevant ticks
202        *component.ticks.added = *component.ticks.changed;
203
204        // SAFETY:
205        // - DeferredWorld ensures archetype pointer will remain valid as no
206        //   relocations will occur.
207        // - component_id exists on this world and this entity
208        // - DISCARD is able to accept ZST events
209        unsafe {
210            let archetype = &*archetype;
211            self.trigger_on_insert(
212                archetype,
213                entity,
214                [component_id].into_iter(),
215                MaybeLocation::caller(),
216                relationship_hook_mode,
217            );
218            if archetype.has_insert_observer() {
219                // SAFETY: the INSERT event_key corresponds to the Insert event's type
220                self.trigger_raw(
221                    INSERT,
222                    &mut InsertEvent { entity },
223                    &mut EntityComponentsTrigger {
224                        components: &[component_id],
225                        old_archetype: Some(archetype),
226                        new_archetype: Some(archetype),
227                    },
228                    MaybeLocation::caller(),
229                );
230            }
231        }
232
233        Ok(Some(result))
234    }
235
236    /// Returns [`EntityMut`]s that expose read and write operations for the
237    /// given `entities`, returning [`Err`] if any of the given entities do not
238    /// exist. Instead of immediately unwrapping the value returned from this
239    /// function, prefer [`World::entity_mut`].
240    ///
241    /// This function supports fetching a single entity or multiple entities:
242    /// - Pass an [`Entity`] to receive a single [`EntityMut`].
243    /// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
244    /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
245    /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
246    ///
247    /// **As [`DeferredWorld`] does not allow structural changes, all returned
248    /// references are [`EntityMut`]s, which do not allow structural changes
249    /// (i.e. adding/removing components or despawning the entity).**
250    ///
251    /// # Errors
252    ///
253    /// - Returns [`EntityMutableFetchError::NotSpawned`] if any of the given `entities` do not exist in the world.
254    ///     - Only the first entity found to be missing will be returned.
255    /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.
256    ///
257    /// # Examples
258    ///
259    /// For examples, see [`DeferredWorld::entity_mut`].
260    ///
261    /// [`EntityMut`]: crate::world::EntityMut
262    /// [`&EntityHashSet`]: crate::entity::EntityHashSet
263    /// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
264    /// [`Vec<EntityMut>`]: alloc::vec::Vec
265    #[inline]
266    pub fn get_entity_mut<F: WorldEntityFetch>(
267        &mut self,
268        entities: F,
269    ) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {
270        let cell = self.as_unsafe_world_cell();
271        // SAFETY: `&mut self` gives mutable access to the entire world,
272        // and prevents any other access to the world.
273        unsafe { entities.fetch_deferred_mut(cell) }
274    }
275
276    /// Returns [`EntityMut`]s that expose read and write operations for the
277    /// given `entities`. This will panic if any of the given entities do not
278    /// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for
279    /// entity existence instead of implicitly panicking.
280    ///
281    /// This function supports fetching a single entity or multiple entities:
282    /// - Pass an [`Entity`] to receive a single [`EntityMut`].
283    /// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
284    /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
285    /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
286    ///
287    /// **As [`DeferredWorld`] does not allow structural changes, all returned
288    /// references are [`EntityMut`]s, which do not allow structural changes
289    /// (i.e. adding/removing components or despawning the entity).**
290    ///
291    /// # Panics
292    ///
293    /// If any of the given `entities` do not exist in the world.
294    ///
295    /// # Examples
296    ///
297    /// ## Single [`Entity`]
298    ///
299    /// ```
300    /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
301    /// #[derive(Component)]
302    /// struct Position {
303    ///   x: f32,
304    ///   y: f32,
305    /// }
306    ///
307    /// # let mut world = World::new();
308    /// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();
309    /// let mut world: DeferredWorld = // ...
310    /// #   DeferredWorld::from(&mut world);
311    ///
312    /// let mut entity_mut = world.entity_mut(entity);
313    /// let mut position = entity_mut.get_mut::<Position>().unwrap();
314    /// position.y = 1.0;
315    /// assert_eq!(position.x, 0.0);
316    /// ```
317    ///
318    /// ## Array of [`Entity`]s
319    ///
320    /// ```
321    /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
322    /// #[derive(Component)]
323    /// struct Position {
324    ///   x: f32,
325    ///   y: f32,
326    /// }
327    ///
328    /// # let mut world = World::new();
329    /// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();
330    /// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();
331    /// let mut world: DeferredWorld = // ...
332    /// #   DeferredWorld::from(&mut world);
333    ///
334    /// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);
335    /// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();
336    /// e1_position.x = 1.0;
337    /// assert_eq!(e1_position.x, 1.0);
338    /// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();
339    /// e2_position.x = 2.0;
340    /// assert_eq!(e2_position.x, 2.0);
341    /// ```
342    ///
343    /// ## Slice of [`Entity`]s
344    ///
345    /// ```
346    /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
347    /// #[derive(Component)]
348    /// struct Position {
349    ///   x: f32,
350    ///   y: f32,
351    /// }
352    ///
353    /// # let mut world = World::new();
354    /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
355    /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
356    /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
357    /// let mut world: DeferredWorld = // ...
358    /// #   DeferredWorld::from(&mut world);
359    ///
360    /// let ids = vec![e1, e2, e3];
361    /// for mut eref in world.entity_mut(&ids[..]) {
362    ///     let mut pos = eref.get_mut::<Position>().unwrap();
363    ///     pos.y = 2.0;
364    ///     assert_eq!(pos.y, 2.0);
365    /// }
366    /// ```
367    ///
368    /// ## [`&EntityHashSet`]
369    ///
370    /// ```
371    /// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};
372    /// #[derive(Component)]
373    /// struct Position {
374    ///   x: f32,
375    ///   y: f32,
376    /// }
377    ///
378    /// # let mut world = World::new();
379    /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
380    /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
381    /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
382    /// let mut world: DeferredWorld = // ...
383    /// #   DeferredWorld::from(&mut world);
384    ///
385    /// let ids = EntityHashSet::from_iter([e1, e2, e3]);
386    /// for (_id, mut eref) in world.entity_mut(&ids) {
387    ///     let mut pos = eref.get_mut::<Position>().unwrap();
388    ///     pos.y = 2.0;
389    ///     assert_eq!(pos.y, 2.0);
390    /// }
391    /// ```
392    ///
393    /// [`EntityMut`]: crate::world::EntityMut
394    /// [`&EntityHashSet`]: crate::entity::EntityHashSet
395    /// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
396    /// [`Vec<EntityMut>`]: alloc::vec::Vec
397    #[inline]
398    pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {
399        self.get_entity_mut(entities).unwrap()
400    }
401
402    /// Simultaneously provides access to entity data and a command queue, which
403    /// will be applied when the [`World`] is next flushed.
404    ///
405    /// This allows using borrowed entity data to construct commands where the
406    /// borrow checker would otherwise prevent it.
407    ///
408    /// See [`World::entities_and_commands`] for the non-deferred version.
409    ///
410    /// # Example
411    ///
412    /// ```rust
413    /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
414    /// #[derive(Component)]
415    /// struct Targets(Vec<Entity>);
416    /// #[derive(Component)]
417    /// struct TargetedBy(Entity);
418    ///
419    /// # let mut _world = World::new();
420    /// # let e1 = _world.spawn_empty().id();
421    /// # let e2 = _world.spawn_empty().id();
422    /// # let eid = _world.spawn(Targets(vec![e1, e2])).id();
423    /// let mut world: DeferredWorld = // ...
424    /// #   DeferredWorld::from(&mut _world);
425    /// let (entities, mut commands) = world.entities_and_commands();
426    ///
427    /// let entity = entities.get(eid).unwrap();
428    /// for &target in entity.get::<Targets>().unwrap().0.iter() {
429    ///     commands.entity(target).insert(TargetedBy(eid));
430    /// }
431    /// # _world.flush();
432    /// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);
433    /// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);
434    /// ```
435    pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {
436        let cell = self.as_unsafe_world_cell();
437        // SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
438        let fetcher = unsafe { EntityFetcher::new(cell) };
439        // SAFETY:
440        // - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
441        // - Command queue access does not conflict with entity access.
442        let commands = unsafe { cell.commands() };
443
444        (fetcher, commands)
445    }
446
447    /// Returns [`Query`] for the given [`QueryState`], which is used to efficiently
448    /// run queries on the [`World`] by storing and reusing the [`QueryState`].
449    ///
450    /// # Panics
451    /// If state is from a different world then self
452    #[inline]
453    #[deprecated(since = "0.19.0", note = "use `QueryState::query_mut`")]
454    pub fn query<'s, D: QueryData, F: QueryFilter>(
455        &mut self,
456        state: &'s mut QueryState<D, F>,
457    ) -> Query<'_, 's, D, F> {
458        state.query_mut(self)
459    }
460
461    /// Gets a mutable reference to the resource of the given type
462    ///
463    /// # Panics
464    ///
465    /// Panics if the resource does not exist.
466    /// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.
467    #[inline]
468    #[track_caller]
469    pub fn resource_mut<R: Resource<Mutability = Mutable>>(&mut self) -> Mut<'_, R> {
470        match self.get_resource_mut() {
471            Some(x) => x,
472            None => panic!(
473                "Requested resource {} does not exist in the `World`.
474                Did you forget to add it using `app.insert_resource` / `app.init_resource`?
475                Resources are also implicitly added via `app.add_message`,
476                and can be added by plugins.",
477                DebugName::type_name::<R>()
478            ),
479        }
480    }
481
482    /// Gets a mutable reference to the resource of the given type if it exists
483    #[inline]
484    pub fn get_resource_mut<R: Resource<Mutability = Mutable>>(&mut self) -> Option<Mut<'_, R>> {
485        // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
486        unsafe { self.world.get_resource_mut() }
487    }
488
489    /// Gets a mutable reference to the non-send data of the given type, if it exists.
490    ///
491    /// # Panics
492    ///
493    /// Panics if the data does not exist.
494    /// Use [`get_non_send_mut`](World::get_non_send_mut) instead if you want to handle this case.
495    ///
496    /// This function will panic if it isn't called from the same thread that the data was inserted from.
497    #[inline]
498    #[track_caller]
499    pub fn non_send_mut<R: 'static>(&mut self) -> Mut<'_, R> {
500        match self.get_non_send_mut() {
501            Some(x) => x,
502            None => panic!(
503                "Requested non-send data {} does not exist in the `World`.
504                Did you forget to add it using `app.insert_non_send` / `app.init_non_send`?
505                Non-send data can also be added by plugins.",
506                DebugName::type_name::<R>()
507            ),
508        }
509    }
510
511    /// Gets a mutable reference to non-send data of the given type, if it exists.
512    /// Otherwise returns `None`.
513    ///
514    /// # Panics
515    /// This function will panic if it isn't called from the same thread that the data was inserted from.
516    #[inline]
517    pub fn get_non_send_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
518        // SAFETY: &mut self ensure that there are no outstanding accesses to the data
519        unsafe { self.world.get_non_send_mut() }
520    }
521
522    /// Writes a [`Message`].
523    /// This method returns the [`MessageId`] of the written `message`,
524    /// or [`None`] if the `message` could not be written.
525    #[inline]
526    pub fn write_message<M: Message>(&mut self, message: M) -> Option<MessageId<M>> {
527        self.write_message_batch(core::iter::once(message))?.next()
528    }
529
530    /// Writes the default value of the [`Message`] of type `E`.
531    /// This method returns the [`MessageId`] of the written `event`,
532    /// or [`None`] if the `event` could not be written.
533    #[inline]
534    pub fn write_message_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {
535        self.write_message(E::default())
536    }
537
538    /// Writes a batch of [`Message`]s from an iterator.
539    /// This method returns the [IDs](`MessageId`) of the written `events`,
540    /// or [`None`] if the `event` could not be written.
541    #[inline]
542    pub fn write_message_batch<E: Message>(
543        &mut self,
544        events: impl IntoIterator<Item = E>,
545    ) -> Option<WriteBatchIds<E>> {
546        let Some(mut events_resource) = self.get_resource_mut::<Messages<E>>() else {
547            log::error!(
548                "Unable to send message `{}`\n\tMessages must be added to the app with `add_message()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_message ",
549                DebugName::type_name::<E>()
550            );
551            return None;
552        };
553        Some(events_resource.write_batch(events))
554    }
555
556    /// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
557    /// The returned pointer may be used to modify the resource, as long as the mutable borrow
558    /// of the [`World`] is still valid.
559    ///
560    /// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
561    /// use this in cases where the actual types are not known at compile time.**
562    #[inline]
563    pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
564        // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
565        unsafe { self.world.get_resource_mut_by_id(component_id) }
566    }
567
568    /// Gets mutable access to `!Send` data with the id [`ComponentId`] if it exists.
569    /// The returned pointer may be used to modify the data, as long as the mutable borrow
570    /// of the [`World`] is still valid.
571    ///
572    /// **You should prefer to use the typed API [`DeferredWorld::get_non_send_mut`] where possible
573    /// and only use this in cases where the actual types are not known at compile time.**
574    ///
575    /// # Panics
576    /// This function will panic if it isn't called from the same thread that the data was inserted from.
577    #[inline]
578    pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
579        // SAFETY: &mut self ensure that there are no outstanding accesses to the data
580        unsafe { self.world.get_non_send_mut_by_id(component_id) }
581    }
582
583    /// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].
584    /// Returns `None` if the `entity` does not have a [`Component`] of the given type.
585    ///
586    /// **You should prefer to use the typed API [`World::get_mut`] where possible and only
587    /// use this in cases where the actual types are not known at compile time.**
588    #[inline]
589    pub fn get_mut_by_id(
590        &mut self,
591        entity: Entity,
592        component_id: ComponentId,
593    ) -> Option<MutUntyped<'_>> {
594        self.get_entity_mut(entity)
595            .ok()?
596            .into_mut_by_id(component_id)
597            .ok()
598    }
599
600    /// Triggers all `on_add` hooks for [`ComponentId`] in target.
601    ///
602    /// # Safety
603    /// Caller must ensure [`ComponentId`] in target exist in self.
604    #[inline]
605    pub(crate) unsafe fn trigger_on_add(
606        &mut self,
607        archetype: &Archetype,
608        entity: Entity,
609        targets: impl Iterator<Item = ComponentId>,
610        caller: MaybeLocation,
611    ) {
612        if archetype.has_add_hook() {
613            for component_id in targets {
614                // SAFETY: Caller ensures that these components exist
615                let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
616                if let Some(hook) = hooks.on_add {
617                    hook(
618                        DeferredWorld { world: self.world },
619                        HookContext {
620                            entity,
621                            component_id,
622                            caller,
623                            relationship_hook_mode: RelationshipHookMode::Run,
624                        },
625                    );
626                }
627            }
628        }
629    }
630
631    /// Triggers all `on_insert` hooks for [`ComponentId`] in target.
632    ///
633    /// # Safety
634    /// Caller must ensure [`ComponentId`] in target exist in self.
635    #[inline]
636    pub(crate) unsafe fn trigger_on_insert(
637        &mut self,
638        archetype: &Archetype,
639        entity: Entity,
640        targets: impl Iterator<Item = ComponentId>,
641        caller: MaybeLocation,
642        relationship_hook_mode: RelationshipHookMode,
643    ) {
644        if archetype.has_insert_hook() {
645            for component_id in targets {
646                // SAFETY: Caller ensures that these components exist
647                let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
648                if let Some(hook) = hooks.on_insert {
649                    hook(
650                        DeferredWorld { world: self.world },
651                        HookContext {
652                            entity,
653                            component_id,
654                            caller,
655                            relationship_hook_mode,
656                        },
657                    );
658                }
659            }
660        }
661    }
662
663    /// Triggers all `on_discard` hooks for [`ComponentId`] in target.
664    ///
665    /// # Safety
666    /// Caller must ensure [`ComponentId`] in target exist in self.
667    #[inline]
668    pub(crate) unsafe fn trigger_on_discard(
669        &mut self,
670        archetype: &Archetype,
671        entity: Entity,
672        targets: impl Iterator<Item = ComponentId>,
673        caller: MaybeLocation,
674        relationship_hook_mode: RelationshipHookMode,
675    ) {
676        if archetype.has_discard_hook() {
677            for component_id in targets {
678                // SAFETY: Caller ensures that these components exist
679                let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
680                if let Some(hook) = hooks.on_discard {
681                    hook(
682                        DeferredWorld { world: self.world },
683                        HookContext {
684                            entity,
685                            component_id,
686                            caller,
687                            relationship_hook_mode,
688                        },
689                    );
690                }
691            }
692        }
693    }
694
695    /// Triggers all `on_remove` hooks for [`ComponentId`] in target.
696    ///
697    /// # Safety
698    /// Caller must ensure [`ComponentId`] in target exist in self.
699    #[inline]
700    pub(crate) unsafe fn trigger_on_remove(
701        &mut self,
702        archetype: &Archetype,
703        entity: Entity,
704        targets: impl Iterator<Item = ComponentId>,
705        caller: MaybeLocation,
706    ) {
707        if archetype.has_remove_hook() {
708            for component_id in targets {
709                // SAFETY: Caller ensures that these components exist
710                let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
711                if let Some(hook) = hooks.on_remove {
712                    hook(
713                        DeferredWorld { world: self.world },
714                        HookContext {
715                            entity,
716                            component_id,
717                            caller,
718                            relationship_hook_mode: RelationshipHookMode::Run,
719                        },
720                    );
721                }
722            }
723        }
724    }
725
726    /// Triggers all `on_despawn` hooks for [`ComponentId`] in target.
727    ///
728    /// # Safety
729    /// Caller must ensure [`ComponentId`] in target exist in self.
730    #[inline]
731    pub(crate) unsafe fn trigger_on_despawn(
732        &mut self,
733        archetype: &Archetype,
734        entity: Entity,
735        targets: impl Iterator<Item = ComponentId>,
736        caller: MaybeLocation,
737    ) {
738        if archetype.has_despawn_hook() {
739            for component_id in targets {
740                // SAFETY: Caller ensures that these components exist
741                let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
742                if let Some(hook) = hooks.on_despawn {
743                    hook(
744                        DeferredWorld { world: self.world },
745                        HookContext {
746                            entity,
747                            component_id,
748                            caller,
749                            relationship_hook_mode: RelationshipHookMode::Run,
750                        },
751                    );
752                }
753            }
754        }
755    }
756
757    /// Triggers all `event` observers for the given `targets`
758    ///
759    /// # Safety
760    /// - Caller must ensure `E` is accessible as the type represented by `event_key`
761    #[inline]
762    pub unsafe fn trigger_raw<'a, E: Event>(
763        &mut self,
764        event_key: EventKey,
765        event: &mut E,
766        trigger: &mut E::Trigger<'a>,
767        caller: MaybeLocation,
768    ) {
769        // SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`
770        let (mut world, observers) = unsafe {
771            let world = self.as_unsafe_world_cell();
772            let observers = world.observers();
773            let Some(observers) = observers.try_get_observers(event_key) else {
774                return;
775            };
776            // SAFETY: The only outstanding reference to world is `observers`
777            (world.into_deferred(), observers)
778        };
779        let context = TriggerContext { event_key, caller };
780
781        // SAFETY:
782        // - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above
783        // - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`
784        // - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.
785        unsafe {
786            trigger.trigger(world.reborrow(), observers, &context, event);
787        }
788    }
789
790    /// Sends a global [`Event`] without any targets.
791    ///
792    /// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.
793    ///
794    /// [`Observer`]: crate::observer::Observer
795    #[track_caller]
796    pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {
797        self.commands().trigger(event);
798    }
799
800    /// Gets an [`UnsafeWorldCell`] containing the underlying world.
801    ///
802    /// # Safety
803    /// - must only be used to make non-structural ECS changes
804    #[inline]
805    pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {
806        self.world
807    }
808
809    /// Gets an [`UnsafeWorldCell`] containing the underlying world.
810    ///
811    /// # Safety
812    /// - must only be used to make non-structural ECS changes
813    #[inline]
814    pub fn into_unsafe_world_cell(self) -> UnsafeWorldCell<'w> {
815        self.world
816    }
817
818    /// Gets the current change tick of [`DeferredWorld`].
819    #[inline]
820    pub fn change_tick(&mut self) -> Tick {
821        self.world.change_tick()
822    }
823}