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