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