diff --git a/benches/benches/bevy_ecs/world/despawn.rs b/benches/benches/bevy_ecs/world/despawn.rs index ace88e744a482..0154febbac13f 100644 --- a/benches/benches/bevy_ecs/world/despawn.rs +++ b/benches/benches/bevy_ecs/world/despawn.rs @@ -18,7 +18,10 @@ pub fn world_despawn(criterion: &mut Criterion) { world.spawn((A(Mat4::default()), B(Vec4::default()))); } - let ents = world.iter_entities().map(|e| e.id()).collect::>(); + let ents = world + .iter_all_entities() + .map(|e| e.id()) + .collect::>(); group.bench_function(format!("{}_entities", entity_count), |bencher| { bencher.iter(|| { ents.iter().for_each(|e| { diff --git a/benches/benches/bevy_ecs/world/despawn_recursive.rs b/benches/benches/bevy_ecs/world/despawn_recursive.rs index dd1ca4325ba22..cbb2bed8576cc 100644 --- a/benches/benches/bevy_ecs/world/despawn_recursive.rs +++ b/benches/benches/bevy_ecs/world/despawn_recursive.rs @@ -22,7 +22,10 @@ pub fn world_despawn_recursive(criterion: &mut Criterion) { }); } - let ents = world.iter_entities().map(|e| e.id()).collect::>(); + let ents = world + .iter_all_entities() + .map(|e| e.id()) + .collect::>(); group.bench_function(format!("{}_entities", entity_count), |bencher| { bencher.iter(|| { ents.iter().for_each(|e| { diff --git a/crates/bevy_ecs/src/world/deferred_world.rs b/crates/bevy_ecs/src/world/deferred_world.rs index 581f1af25e71e..f6ac8cbfdc110 100644 --- a/crates/bevy_ecs/src/world/deferred_world.rs +++ b/crates/bevy_ecs/src/world/deferred_world.rs @@ -4,7 +4,7 @@ use crate::{ archetype::Archetype, change_detection::{MaybeLocation, MutUntyped}, component::{ComponentId, HookContext, Mutable}, - entity::Entity, + entity::{Entity, EntitySet, EntitySetIterator, TrustedEntityBorrow, UniqueEntityArray}, event::{Event, EventId, Events, SendBatchIds}, observer::{Observers, TriggerTargets}, prelude::{Component, QueryState}, @@ -12,7 +12,7 @@ use crate::{ resource::Resource, system::{Commands, Query}, traversal::Traversal, - world::{error::EntityMutableFetchError, WorldEntityFetch}, + world::{error::EntityMutableFetchError, EntityDoesNotExistError, EntityMut}, }; use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World, ON_INSERT, ON_REPLACE}; @@ -173,142 +173,137 @@ impl<'w> DeferredWorld<'w> { Ok(Some(result)) } - /// Returns [`EntityMut`]s that expose read and write operations for the - /// given `entities`, returning [`Err`] if any of the given entities do not - /// exist. Instead of immediately unwrapping the value returned from this - /// function, prefer [`World::entity_mut`]. - /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityMut`]. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap`]. - /// - /// **As [`DeferredWorld`] does not allow structural changes, all returned - /// references are [`EntityMut`]s, which do not allow structural changes - /// (i.e. adding/removing components or despawning the entity).** + /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. /// /// # Errors /// - /// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if any of the given `entities` do not exist in the world. - /// - Only the first entity found to be missing will be returned. - /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times. + /// [`EntityDoesNotExistError`] if any entity does not exist in the world. /// - /// # Examples + /// ``` + /// use bevy_ecs::{component::Component, world::World}; /// - /// For examples, see [`DeferredWorld::entity_mut`]. + /// #[derive(Component)] + /// struct Position { + /// x: f32, + /// y: f32, + /// } /// - /// [`EntityMut`]: crate::world::EntityMut - /// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet - /// [`EntityHashMap`]: crate::entity::hash_map::EntityHashMap - /// [`Vec`]: alloc::vec::Vec + /// let mut world = World::new(); + /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); + /// let mut entity_mut = world.get_entity_mut(entity).unwrap(); + /// let mut position = entity_mut.get_mut::().unwrap(); + /// position.x = 1.0; + /// ``` #[inline] - pub fn get_entity_mut( + pub fn get_entity_mut( &mut self, - entities: F, - ) -> Result, EntityMutableFetchError> { + entity: Entity, + ) -> Result, EntityMutableFetchError> { let cell = self.as_unsafe_world_cell(); - // SAFETY: `&mut self` gives mutable access to the entire world, - // and prevents any other access to the world. - unsafe { entities.fetch_deferred_mut(cell) } + let ecell = cell.get_entity(entity)?; + // SAFETY: caller ensures that the world cell has mutable access to the entity. + Ok(unsafe { EntityMut::new(ecell) }) } - /// Returns [`EntityMut`]s that expose read and write operations for the - /// given `entities`. This will panic if any of the given entities do not - /// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for - /// entity existence instead of implicitly panicking. - /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityMut`]. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap`]. - /// - /// **As [`DeferredWorld`] does not allow structural changes, all returned - /// references are [`EntityMut`]s, which do not allow structural changes - /// (i.e. adding/removing components or despawning the entity).** - /// - /// # Panics - /// - /// If any of the given `entities` do not exist in the world. - /// - /// # Examples - /// - /// ## Single [`Entity`] + /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. + /// This will panic if the `entity` does not exist. Use [`DeferredWorld::get_entity_mut`] if you want + /// to check for entity existence instead of implicitly panic-ing. /// /// ``` - /// # use bevy_ecs::{prelude::*, world::DeferredWorld}; + /// use bevy_ecs::{component::Component, world::World}; + /// /// #[derive(Component)] /// struct Position { /// x: f32, /// y: f32, /// } /// - /// # let mut world = World::new(); - /// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// let mut world: DeferredWorld = // ... - /// # DeferredWorld::from(&mut world); - /// + /// let mut world = World::new(); + /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); /// let mut entity_mut = world.entity_mut(entity); /// let mut position = entity_mut.get_mut::().unwrap(); - /// position.y = 1.0; - /// assert_eq!(position.x, 0.0); + /// position.x = 1.0; /// ``` + #[inline] + pub fn entity_mut(&mut self, entity: Entity) -> EntityMut<'_> { + self.get_entity_mut(entity).unwrap() + } + + /// Gets mutable access to multiple entities. /// - /// ## Array of [`Entity`]s + /// # Errors + /// + /// - [`EntityMutableFetchError::EntityDoesNotExist`] if any entities do not exist in the world + /// - [`EntityMutableFetchError::AliasedMutability`] if the same entity is specified multiple times + /// + /// # Examples /// /// ``` /// # use bevy_ecs::{prelude::*, world::DeferredWorld}; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// /// # let mut world = World::new(); - /// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); /// let mut world: DeferredWorld = // ... /// # DeferredWorld::from(&mut world); /// - /// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]); - /// let mut e1_position = e1_ref.get_mut::().unwrap(); - /// e1_position.x = 1.0; - /// assert_eq!(e1_position.x, 1.0); - /// let mut e2_position = e2_ref.get_mut::().unwrap(); - /// e2_position.x = 2.0; - /// assert_eq!(e2_position.x, 2.0); + /// // Disjoint mutable access. + /// let [entity1, entity2] = world.get_many_entities_mut([id1, id2]).unwrap(); + /// + /// // Trying to access the same entity multiple times will fail. + /// assert!(world.get_many_entities_mut([id1, id1]).is_err()); /// ``` + pub fn get_many_entities_mut( + &mut self, + entities: [T; N], + ) -> Result<[EntityMut<'_>; N], EntityMutableFetchError> { + // SAFETY: We have mutable access to the entire world + unsafe { self.as_unsafe_world_cell().get_many_entities_mut(entities) } + } + + /// Gets mutable access to multiple entities. /// - /// ## Slice of [`Entity`]s + /// This takes a [`UniqueEntityArray`], which asserts that the entities are + /// all unique so that it doesn't need to perform additional checks. /// - /// ``` - /// # use bevy_ecs::{prelude::*, world::DeferredWorld}; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } + /// # Errors + /// + /// - [`EntityDoesNotExistError`] if any entities do not exist in the world /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::DeferredWorld, entity::UniqueEntityArray}; /// # let mut world = World::new(); - /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); /// let mut world: DeferredWorld = // ... /// # DeferredWorld::from(&mut world); /// - /// let ids = vec![e1, e2, e3]; - /// for mut eref in world.entity_mut(&ids[..]) { - /// let mut pos = eref.get_mut::().unwrap(); - /// pos.y = 2.0; - /// assert_eq!(pos.y, 2.0); - /// } + /// // Assert that the IDs are disjoint + /// let array = unsafe { UniqueEntityArray::from_array_unchecked([id1, id2]) }; + /// let [entity1, entity2] = world.get_many_entities_unique_mut(array).unwrap(); /// ``` + pub fn get_many_entities_unique_mut( + &mut self, + entities: UniqueEntityArray, + ) -> Result<[EntityMut<'_>; N], EntityDoesNotExistError> { + // SAFETY: We have mutable access to the entire world + unsafe { + self.as_unsafe_world_cell() + .get_many_entities_unique_mut(entities) + } + } + + /// Gets mutable access to multiple entities. + /// Any entities that do not exist in the world are filtered out. /// - /// ## [`&EntityHashSet`] + /// This takes a [`EntitySet`], which asserts that the entities are + /// all unique so that it doesn't need to perform additional checks. + /// + /// # Examples /// /// ``` - /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet, world::DeferredWorld}; + ///# use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet, world::DeferredWorld}; /// #[derive(Component)] /// struct Position { /// x: f32, @@ -323,20 +318,18 @@ impl<'w> DeferredWorld<'w> { /// # DeferredWorld::from(&mut world); /// /// let ids = EntityHashSet::from_iter([e1, e2, e3]); - /// for (_id, mut eref) in world.entity_mut(&ids) { + /// for mut eref in world.iter_entities_mut(&ids) { /// let mut pos = eref.get_mut::().unwrap(); /// pos.y = 2.0; /// assert_eq!(pos.y, 2.0); /// } /// ``` - /// - /// [`EntityMut`]: crate::world::EntityMut - /// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet - /// [`EntityHashMap`]: crate::entity::hash_map::EntityHashMap - /// [`Vec`]: alloc::vec::Vec - #[inline] - pub fn entity_mut(&mut self, entities: F) -> F::DeferredMut<'_> { - self.get_entity_mut(entities).unwrap() + pub fn iter_entities_mut( + &mut self, + entities: impl EntitySet, + ) -> impl EntitySetIterator> { + // SAFETY: We have mutable access to the entire world + unsafe { self.as_unsafe_world_cell().iter_entities_mut(entities) } } /// Returns [`Query`] for the given [`QueryState`], which is used to efficiently diff --git a/crates/bevy_ecs/src/world/entity_fetch.rs b/crates/bevy_ecs/src/world/entity_fetch.rs deleted file mode 100644 index e731582f48b85..0000000000000 --- a/crates/bevy_ecs/src/world/entity_fetch.rs +++ /dev/null @@ -1,342 +0,0 @@ -use alloc::vec::Vec; -use core::mem::MaybeUninit; - -use crate::{ - entity::{hash_map::EntityHashMap, hash_set::EntityHashSet, Entity, EntityDoesNotExistError}, - world::{ - error::EntityMutableFetchError, unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, - EntityWorldMut, - }, -}; - -/// Types that can be used to fetch [`Entity`] references from a [`World`]. -/// -/// Provided implementations are: -/// - [`Entity`]: Fetch a single entity. -/// - `[Entity; N]`/`&[Entity; N]`: Fetch multiple entities, receiving a -/// same-sized array of references. -/// - `&[Entity]`: Fetch multiple entities, receiving a vector of references. -/// - [`&EntityHashSet`](EntityHashSet): Fetch multiple entities, receiving a -/// hash map of [`Entity`] IDs to references. -/// -/// # Performance -/// -/// - The slice and array implementations perform an aliased mutability check -/// in [`WorldEntityFetch::fetch_mut`] that is `O(N^2)`. -/// - The single [`Entity`] implementation performs no such check as only one -/// reference is returned. -/// -/// # Safety -/// -/// Implementor must ensure that: -/// - No aliased mutability is caused by the returned references. -/// - [`WorldEntityFetch::fetch_ref`] returns only read-only references. -/// - [`WorldEntityFetch::fetch_deferred_mut`] returns only non-structurally-mutable references. -/// -/// [`World`]: crate::world::World -pub unsafe trait WorldEntityFetch { - /// The read-only reference type returned by [`WorldEntityFetch::fetch_ref`]. - type Ref<'w>; - - /// The mutable reference type returned by [`WorldEntityFetch::fetch_mut`]. - type Mut<'w>; - - /// The mutable reference type returned by [`WorldEntityFetch::fetch_deferred_mut`], - /// but without structural mutability. - type DeferredMut<'w>; - - /// Returns read-only reference(s) to the entities with the given - /// [`Entity`] IDs, as determined by `self`. - /// - /// # Safety - /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeWorldCell`] has read-only access to the fetched entities. - /// - No other mutable references to the fetched entities exist at the same time. - /// - /// # Errors - /// - /// - Returns [`EntityDoesNotExistError`] if the entity does not exist. - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError>; - - /// Returns mutable reference(s) to the entities with the given [`Entity`] - /// IDs, as determined by `self`. - /// - /// # Safety - /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeWorldCell`] has mutable access to the fetched entities. - /// - No other references to the fetched entities exist at the same time. - /// - /// # Errors - /// - /// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if the entity does not exist. - /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the entity was - /// requested mutably more than once. - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError>; - - /// Returns mutable reference(s) to the entities with the given [`Entity`] - /// IDs, as determined by `self`, but without structural mutability. - /// - /// No structural mutability means components cannot be removed from the - /// entity, new components cannot be added to the entity, and the entity - /// cannot be despawned. - /// - /// # Safety - /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeWorldCell`] has mutable access to the fetched entities. - /// - No other references to the fetched entities exist at the same time. - /// - /// # Errors - /// - /// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if the entity does not exist. - /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the entity was - /// requested mutably more than once. - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError>; -} - -// SAFETY: -// - No aliased mutability is caused because a single reference is returned. -// - No mutable references are returned by `fetch_ref`. -// - No structurally-mutable references are returned by `fetch_deferred_mut`. -unsafe impl WorldEntityFetch for Entity { - type Ref<'w> = EntityRef<'w>; - type Mut<'w> = EntityWorldMut<'w>; - type DeferredMut<'w> = EntityMut<'w>; - - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError> { - let ecell = cell.get_entity(self)?; - // SAFETY: caller ensures that the world cell has read-only access to the entity. - Ok(unsafe { EntityRef::new(ecell) }) - } - - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - let location = cell - .entities() - .get(self) - .ok_or(EntityDoesNotExistError::new(self, cell.entities()))?; - // SAFETY: caller ensures that the world cell has mutable access to the entity. - let world = unsafe { cell.world_mut() }; - // SAFETY: location was fetched from the same world's `Entities`. - Ok(unsafe { EntityWorldMut::new(world, self, location) }) - } - - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - let ecell = cell.get_entity(self)?; - // SAFETY: caller ensures that the world cell has mutable access to the entity. - Ok(unsafe { EntityMut::new(ecell) }) - } -} - -// SAFETY: -// - No aliased mutability is caused because the array is checked for duplicates. -// - No mutable references are returned by `fetch_ref`. -// - No structurally-mutable references are returned by `fetch_deferred_mut`. -unsafe impl WorldEntityFetch for [Entity; N] { - type Ref<'w> = [EntityRef<'w>; N]; - type Mut<'w> = [EntityMut<'w>; N]; - type DeferredMut<'w> = [EntityMut<'w>; N]; - - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError> { - <&Self>::fetch_ref(&self, cell) - } - - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - <&Self>::fetch_mut(&self, cell) - } - - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - <&Self>::fetch_deferred_mut(&self, cell) - } -} - -// SAFETY: -// - No aliased mutability is caused because the array is checked for duplicates. -// - No mutable references are returned by `fetch_ref`. -// - No structurally-mutable references are returned by `fetch_deferred_mut`. -unsafe impl WorldEntityFetch for &'_ [Entity; N] { - type Ref<'w> = [EntityRef<'w>; N]; - type Mut<'w> = [EntityMut<'w>; N]; - type DeferredMut<'w> = [EntityMut<'w>; N]; - - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError> { - let mut refs = [MaybeUninit::uninit(); N]; - for (r, &id) in core::iter::zip(&mut refs, self) { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has read-only access to the entity. - *r = MaybeUninit::new(unsafe { EntityRef::new(ecell) }); - } - - // SAFETY: Each item was initialized in the loop above. - let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) }); - - Ok(refs) - } - - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - // Check for duplicate entities. - for i in 0..self.len() { - for j in 0..i { - if self[i] == self[j] { - return Err(EntityMutableFetchError::AliasedMutability(self[i])); - } - } - } - - let mut refs = [const { MaybeUninit::uninit() }; N]; - for (r, &id) in core::iter::zip(&mut refs, self) { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has mutable access to the entity. - *r = MaybeUninit::new(unsafe { EntityMut::new(ecell) }); - } - - // SAFETY: Each item was initialized in the loop above. - let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) }); - - Ok(refs) - } - - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - // SAFETY: caller ensures that the world cell has mutable access to the entity, - // and `fetch_mut` does not return structurally-mutable references. - unsafe { self.fetch_mut(cell) } - } -} - -// SAFETY: -// - No aliased mutability is caused because the slice is checked for duplicates. -// - No mutable references are returned by `fetch_ref`. -// - No structurally-mutable references are returned by `fetch_deferred_mut`. -unsafe impl WorldEntityFetch for &'_ [Entity] { - type Ref<'w> = Vec>; - type Mut<'w> = Vec>; - type DeferredMut<'w> = Vec>; - - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError> { - let mut refs = Vec::with_capacity(self.len()); - for &id in self { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has read-only access to the entity. - refs.push(unsafe { EntityRef::new(ecell) }); - } - - Ok(refs) - } - - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - // Check for duplicate entities. - for i in 0..self.len() { - for j in 0..i { - if self[i] == self[j] { - return Err(EntityMutableFetchError::AliasedMutability(self[i])); - } - } - } - - let mut refs = Vec::with_capacity(self.len()); - for &id in self { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has mutable access to the entity. - refs.push(unsafe { EntityMut::new(ecell) }); - } - - Ok(refs) - } - - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - // SAFETY: caller ensures that the world cell has mutable access to the entity, - // and `fetch_mut` does not return structurally-mutable references. - unsafe { self.fetch_mut(cell) } - } -} - -// SAFETY: -// - No aliased mutability is caused because `EntityHashSet` guarantees no duplicates. -// - No mutable references are returned by `fetch_ref`. -// - No structurally-mutable references are returned by `fetch_deferred_mut`. -unsafe impl WorldEntityFetch for &'_ EntityHashSet { - type Ref<'w> = EntityHashMap>; - type Mut<'w> = EntityHashMap>; - type DeferredMut<'w> = EntityHashMap>; - - unsafe fn fetch_ref( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityDoesNotExistError> { - let mut refs = EntityHashMap::with_capacity(self.len()); - for &id in self { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has read-only access to the entity. - refs.insert(id, unsafe { EntityRef::new(ecell) }); - } - Ok(refs) - } - - unsafe fn fetch_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - let mut refs = EntityHashMap::with_capacity(self.len()); - for &id in self { - let ecell = cell.get_entity(id)?; - // SAFETY: caller ensures that the world cell has mutable access to the entity. - refs.insert(id, unsafe { EntityMut::new(ecell) }); - } - Ok(refs) - } - - unsafe fn fetch_deferred_mut( - self, - cell: UnsafeWorldCell<'_>, - ) -> Result, EntityMutableFetchError> { - // SAFETY: caller ensures that the world cell has mutable access to the entity, - // and `fetch_mut` does not return structurally-mutable references. - unsafe { self.fetch_mut(cell) } - } -} diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index ab4b9dd4de931..0bbf718b90b70 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -5462,7 +5462,7 @@ mod tests { let x_id = world.register_component::(); let y_id = world.register_component::(); - let e1_mut = &world.get_entity_mut([e1]).unwrap()[0]; + let e1_mut = &world.get_entity_mut(e1).unwrap().into_mutable(); // SAFETY: The entity e1 contains component X. let x_ptr = unsafe { e1_mut.get_mut_by_id_unchecked(x_id) }.unwrap(); // SAFETY: The entity e1 contains component Y, with components X and Y being mutually independent. diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 294145de23049..3ff0e3caaf0f8 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -3,7 +3,6 @@ pub(crate) mod command_queue; mod component_constants; mod deferred_world; -mod entity_fetch; mod entity_ref; pub mod error; mod filtered_resource; @@ -21,7 +20,6 @@ pub use crate::{ pub use bevy_ecs_macros::FromWorld; pub use component_constants::*; pub use deferred_world::DeferredWorld; -pub use entity_fetch::WorldEntityFetch; pub use entity_ref::{ DynamicComponentFetch, EntityMut, EntityMutExcept, EntityRef, EntityRefExcept, EntityWorldMut, Entry, FilteredEntityMut, FilteredEntityRef, OccupiedEntry, TryFromFilteredError, VacantEntry, @@ -42,7 +40,8 @@ use crate::{ Components, Mutable, RequiredComponents, RequiredComponentsError, Tick, }, entity::{ - AllocAtWithoutReplacement, Entities, Entity, EntityDoesNotExistError, EntityLocation, + AllocAtWithoutReplacement, Entities, Entity, EntityBorrow, EntityDoesNotExistError, + EntityLocation, EntitySet, EntitySetIterator, TrustedEntityBorrow, UniqueEntityArray, }, entity_disabling::DefaultQueryFilters, event::{Event, EventId, Events, SendBatchIds}, @@ -63,7 +62,7 @@ use crate::{ use alloc::{boxed::Box, vec::Vec}; use bevy_platform_support::sync::atomic::{AtomicU32, Ordering}; use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref}; -use core::{any::TypeId, fmt}; +use core::{any::TypeId, fmt, mem::MaybeUninit}; use log::warn; use unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell}; @@ -590,26 +589,13 @@ impl World { self.components.get_resource_id(TypeId::of::()) } - /// Returns [`EntityRef`]s that expose read-only operations for the given - /// `entities`. This will panic if any of the given entities do not exist. Use - /// [`World::get_entity`] if you want to check for entity existence instead - /// of implicitly panicking. - /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityRef`]. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityRef`]s. - /// - /// # Panics - /// - /// If any of the given `entities` do not exist in the world. - /// - /// # Examples - /// - /// ## Single [`Entity`] + /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`. + /// This will panic if the `entity` does not exist. Use [`World::get_entity`] if you want + /// to check for entity existence instead of implicitly panic-ing. /// /// ``` - /// # use bevy_ecs::prelude::*; + /// use bevy_ecs::{component::Component, world::World}; + /// /// #[derive(Component)] /// struct Position { /// x: f32, @@ -618,78 +604,12 @@ impl World { /// /// let mut world = World::new(); /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// /// let position = world.entity(entity).get::().unwrap(); /// assert_eq!(position.x, 0.0); /// ``` - /// - /// ## Array of [`Entity`]s - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id(); - /// - /// let [e1_ref, e2_ref] = world.entity([e1, e2]); - /// let e1_position = e1_ref.get::().unwrap(); - /// assert_eq!(e1_position.x, 0.0); - /// let e2_position = e2_ref.get::().unwrap(); - /// assert_eq!(e2_position.x, 1.0); - /// ``` - /// - /// ## Slice of [`Entity`]s - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// - /// let ids = vec![e1, e2, e3]; - /// for eref in world.entity(&ids[..]) { - /// assert_eq!(eref.get::().unwrap().y, 1.0); - /// } - /// ``` - /// - /// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) - /// - /// ``` - /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet}; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// - /// let ids = EntityHashSet::from_iter([e1, e2, e3]); - /// for (_id, eref) in world.entity(&ids) { - /// assert_eq!(eref.get::().unwrap().y, 1.0); - /// } - /// ``` - /// - /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] #[track_caller] - pub fn entity(&self, entities: F) -> F::Ref<'_> { + pub fn entity(&self, entity: Entity) -> EntityRef<'_> { #[inline(never)] #[cold] #[track_caller] @@ -700,42 +620,19 @@ impl World { ); } - match self.get_entity(entities) { + match self.get_entity(entity) { Ok(fetched) => fetched, Err(error) => panic_no_entity(self, error.entity), } } - /// Returns [`EntityMut`]s that expose read and write operations for the - /// given `entities`. This will panic if any of the given entities do not - /// exist. Use [`World::get_entity_mut`] if you want to check for entity - /// existence instead of implicitly panicking. - /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityWorldMut`]. - /// - This reference type allows for structural changes to the entity, - /// such as adding or removing components, or despawning the entity. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). - /// - /// In order to perform structural changes on the returned entity reference, - /// such as adding or removing components, or despawning the entity, only a - /// single [`Entity`] can be passed to this function. Allowing multiple - /// entities at the same time with structural access would lead to undefined - /// behavior, so [`EntityMut`] is returned when requesting multiple entities. - /// - /// # Panics - /// - /// If any of the given `entities` do not exist in the world. - /// - /// # Examples - /// - /// ## Single [`Entity`] + /// Retrieves an [`EntityWorldMut`] that exposes read and write operations for the given `entity`. + /// This will panic if the `entity` does not exist. Use [`World::get_entity_mut`] if you want + /// to check for entity existence instead of implicitly panic-ing. /// /// ``` - /// # use bevy_ecs::prelude::*; + /// use bevy_ecs::{component::Component, world::World}; + /// /// #[derive(Component)] /// struct Position { /// x: f32, @@ -744,88 +641,13 @@ impl World { /// /// let mut world = World::new(); /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// /// let mut entity_mut = world.entity_mut(entity); /// let mut position = entity_mut.get_mut::().unwrap(); - /// position.y = 1.0; - /// assert_eq!(position.x, 0.0); - /// entity_mut.despawn(); - /// # assert!(world.get_entity_mut(entity).is_err()); - /// ``` - /// - /// ## Array of [`Entity`]s - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id(); - /// let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id(); - /// - /// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]); - /// let mut e1_position = e1_ref.get_mut::().unwrap(); - /// e1_position.x = 1.0; - /// assert_eq!(e1_position.x, 1.0); - /// let mut e2_position = e2_ref.get_mut::().unwrap(); - /// e2_position.x = 2.0; - /// assert_eq!(e2_position.x, 2.0); - /// ``` - /// - /// ## Slice of [`Entity`]s - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// - /// let ids = vec![e1, e2, e3]; - /// for mut eref in world.entity_mut(&ids[..]) { - /// let mut pos = eref.get_mut::().unwrap(); - /// pos.y = 2.0; - /// assert_eq!(pos.y, 2.0); - /// } - /// ``` - /// - /// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) - /// - /// ``` - /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet}; - /// #[derive(Component)] - /// struct Position { - /// x: f32, - /// y: f32, - /// } - /// - /// let mut world = World::new(); - /// let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); - /// - /// let ids = EntityHashSet::from_iter([e1, e2, e3]); - /// for (_id, mut eref) in world.entity_mut(&ids) { - /// let mut pos = eref.get_mut::().unwrap(); - /// pos.y = 2.0; - /// assert_eq!(pos.y, 2.0); - /// } + /// position.x = 1.0; /// ``` - /// - /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] #[track_caller] - pub fn entity_mut(&mut self, entities: F) -> F::Mut<'_> { + pub fn entity_mut(&mut self, entity: Entity) -> EntityWorldMut<'_> { #[inline(never)] #[cold] #[track_caller] @@ -833,7 +655,7 @@ impl World { panic!("{e}"); } - match self.get_entity_mut(entities) { + match self.get_entity_mut(entity) { Ok(fetched) => fetched, Err(e) => panic_on_err(e), } @@ -860,85 +682,244 @@ impl World { .filter_map(|id| self.components().get_info(id))) } - /// Returns [`EntityRef`]s that expose read-only operations for the given - /// `entities`, returning [`Err`] if any of the given entities do not exist. - /// Instead of immediately unwrapping the value returned from this function, - /// prefer [`World::entity`]. - /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityRef`]. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityRef`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). + /// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`. /// /// # Errors /// - /// If any of the given `entities` do not exist in the world, the first - /// [`Entity`] found to be missing will return an [`EntityDoesNotExistError`]. + /// [`EntityDoesNotExistError`] if any entity does not exist in the world. /// - /// # Examples + /// # Example + /// + /// ``` + /// use bevy_ecs::{component::Component, world::World}; /// - /// For examples, see [`World::entity`]. + /// #[derive(Component)] + /// struct Position { + /// x: f32, + /// y: f32, + /// } /// - /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet + /// let mut world = World::new(); + /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); + /// let entity_ref = world.get_entity(entity).unwrap(); + /// let position = entity_ref.get::().unwrap(); + /// assert_eq!(position.x, 0.0); + /// ``` #[inline] - pub fn get_entity( - &self, - entities: F, - ) -> Result, EntityDoesNotExistError> { + pub fn get_entity(&self, entity: Entity) -> Result, EntityDoesNotExistError> { let cell = self.as_unsafe_world_cell_readonly(); + let ecell = cell.get_entity(entity)?; // SAFETY: `&self` gives read access to the entire world, and prevents mutable access. - unsafe { entities.fetch_ref(cell) } + Ok(unsafe { EntityRef::new(ecell) }) + } + + /// Gets an [`EntityRef`] for multiple entities at once. + /// + /// # Errors + /// + /// [`EntityDoesNotExistError`] if any entity does not exist in the world. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Getting multiple entities. + /// let [entity1, entity2] = world.get_many_entities([id1, id2]).unwrap(); + /// + /// // Trying to get a despawned entity will fail. + /// world.despawn(id2); + /// assert!(world.get_many_entities([id1, id2]).is_err()); + /// ``` + pub fn get_many_entities( + &self, + entities: [Entity; N], + ) -> Result<[EntityRef<'_>; N], EntityDoesNotExistError> { + let cell = self.as_unsafe_world_cell_readonly(); + + let mut refs = [MaybeUninit::uninit(); N]; + for (r, id) in core::iter::zip(&mut refs, entities) { + let ecell = cell.get_entity(id)?; + // SAFETY: `&self` gives read access to the entire world, and prevents mutable access. + *r = MaybeUninit::new(unsafe { EntityRef::new(ecell) }); + } + + // SAFETY: Each item was initialized in the loop above. + let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) }); + + Ok(refs) } - /// Returns [`EntityMut`]s that expose read and write operations for the - /// given `entities`, returning [`Err`] if any of the given entities do not - /// exist. Instead of immediately unwrapping the value returned from this - /// function, prefer [`World::entity_mut`]. + /// Gets an [`EntityRef`] for multiple entities at once. + /// Any entities that do not exist in the world are filtered out. /// - /// This function supports fetching a single entity or multiple entities: - /// - Pass an [`Entity`] to receive a single [`EntityWorldMut`]. - /// - This reference type allows for structural changes to the entity, - /// such as adding or removing components, or despawning the entity. - /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. - /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// // Getting multiple entities. + /// let entities: Vec = world.iter_entities([id1, id2]).collect(); + /// assert_eq!(entities.len(), 2); /// - /// In order to perform structural changes on the returned entity reference, - /// such as adding or removing components, or despawning the entity, only a - /// single [`Entity`] can be passed to this function. Allowing multiple - /// entities at the same time with structural access would lead to undefined - /// behavior, so [`EntityMut`] is returned when requesting multiple entities. + /// // Despawned entities will be excluded. + /// world.despawn(id2); + /// let entities: Vec = world.iter_entities([id1, id2]).collect(); + /// assert_eq!(entities.len(), 1); + /// ``` + pub fn iter_entities>( + &self, + entities: I, + ) -> impl Iterator> { + entities + .into_iter() + .filter_map(|e| self.get_entity(e.entity()).ok()) + } + + /// Retrieves an [`EntityWorldMut`] that exposes read and write operations for the given `entity`. /// /// # Errors /// - /// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if any of the given `entities` do not exist in the world. - /// - Only the first entity found to be missing will be returned. - /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times. + /// [`EntityDoesNotExistError`] if any entity does not exist in the world. /// - /// # Examples + /// ``` + /// use bevy_ecs::{component::Component, world::World}; /// - /// For examples, see [`World::entity_mut`]. + /// #[derive(Component)] + /// struct Position { + /// x: f32, + /// y: f32, + /// } /// - /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet + /// let mut world = World::new(); + /// let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id(); + /// let mut entity_mut = world.get_entity_mut(entity).unwrap(); + /// let mut position = entity_mut.get_mut::().unwrap(); + /// position.x = 1.0; + /// ``` #[inline] - pub fn get_entity_mut( + pub fn get_entity_mut( &mut self, - entities: F, - ) -> Result, EntityMutableFetchError> { + entity: Entity, + ) -> Result, EntityMutableFetchError> { let cell = self.as_unsafe_world_cell(); - // SAFETY: `&mut self` gives mutable access to the entire world, - // and prevents any other access to the world. - unsafe { entities.fetch_mut(cell) } + let location = cell + .entities() + .get(entity) + .ok_or(EntityDoesNotExistError::new(entity, cell.entities()))?; + // SAFETY: We have mutable access to the entire world + let world = unsafe { cell.world_mut() }; + // SAFETY: location was fetched from the same world's `Entities`. + Ok(unsafe { EntityWorldMut::new(world, entity, location) }) + } + + /// Gets mutable access to multiple entities. + /// + /// # Errors + /// + /// - [`EntityMutableFetchError::EntityDoesNotExist`] if any entities do not exist in the world + /// - [`EntityMutableFetchError::AliasedMutability`] if the same entity is specified multiple times + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// + /// // Disjoint mutable access. + /// let [entity1, entity2] = world.get_many_entities_mut([id1, id2]).unwrap(); + /// + /// // Trying to access the same entity multiple times will fail. + /// assert!(world.get_many_entities_mut([id1, id1]).is_err()); + /// ``` + pub fn get_many_entities_mut( + &mut self, + entities: [T; N], + ) -> Result<[EntityMut<'_>; N], EntityMutableFetchError> { + // SAFETY: We have mutable access to the entire world + unsafe { self.as_unsafe_world_cell().get_many_entities_mut(entities) } + } + + /// Gets mutable access to multiple entities. + /// + /// This takes a [`UniqueEntityArray`], which asserts that the entities are + /// all unique so that it doesn't need to perform additional checks. + /// + /// # Errors + /// + /// - [`EntityDoesNotExistError`] if any entities do not exist in the world + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # use bevy_ecs::entity::UniqueEntityArray; + /// let mut world = World::new(); + /// # let id1 = world.spawn_empty().id(); + /// # let id2 = world.spawn_empty().id(); + /// + /// // Assert that the IDs are disjoint + /// let array = unsafe { UniqueEntityArray::from_array_unchecked([id1, id2]) }; + /// let [entity1, entity2] = world.get_many_entities_unique_mut(array).unwrap(); + /// ``` + pub fn get_many_entities_unique_mut( + &mut self, + entities: UniqueEntityArray, + ) -> Result<[EntityMut<'_>; N], EntityDoesNotExistError> { + // SAFETY: We have mutable access to the entire world + unsafe { + self.as_unsafe_world_cell() + .get_many_entities_unique_mut(entities) + } + } + + /// Gets mutable access to multiple entities. + /// Any entities that do not exist in the world are filtered out. + /// + /// This takes a [`EntitySet`], which asserts that the entities are + /// all unique so that it doesn't need to perform additional checks. + /// + /// # Examples + /// + /// ``` + ///# use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet, world::DeferredWorld}; + /// #[derive(Component)] + /// struct Position { + /// x: f32, + /// y: f32, + /// } + /// + /// let mut world = World::new(); + /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); + /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); + /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id(); + /// + /// let ids = EntityHashSet::from_iter([e1, e2, e3]); + /// for mut eref in world.iter_entities_mut(&ids) { + /// let mut pos = eref.get_mut::().unwrap(); + /// pos.y = 2.0; + /// assert_eq!(pos.y, 2.0); + /// } + /// ``` + pub fn iter_entities_mut( + &mut self, + entities: impl EntitySet, + ) -> impl EntitySetIterator> { + // SAFETY: We have mutable access to the entire world + unsafe { self.as_unsafe_world_cell().iter_entities_mut(entities) } } /// Returns an [`Entity`] iterator of current entities. /// /// This is useful in contexts where you only have read-only access to the [`World`]. #[inline] - pub fn iter_entities(&self) -> impl Iterator> + '_ { + pub fn iter_all_entities(&self) -> impl Iterator> + '_ { self.archetypes.iter().flat_map(|archetype| { archetype .entities() @@ -966,7 +947,7 @@ impl World { } /// Returns a mutable iterator over all entities in the `World`. - pub fn iter_entities_mut(&mut self) -> impl Iterator> + '_ { + pub fn iter_all_entities_mut(&mut self) -> impl Iterator> + '_ { let world_cell = self.as_unsafe_world_cell(); world_cell.archetypes().iter().flat_map(move |archetype| { archetype @@ -3605,7 +3586,6 @@ mod tests { borrow::ToOwned, string::{String, ToString}, sync::Arc, - vec, vec::Vec, }; use bevy_ecs_macros::Component; @@ -4028,7 +4008,7 @@ mod tests { let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| { entity_counters.clear(); - for entity in world.iter_entities() { + for entity in world.iter_all_entities() { let counter = entity_counters.entry(entity.id()).or_insert(0); *counter += 1; } @@ -4105,7 +4085,7 @@ mod tests { let b1 = world.spawn(B(1)).id(); let b2 = world.spawn(B(2)).id(); - for mut entity in world.iter_entities_mut() { + for mut entity in world.iter_all_entities_mut() { if let Some(mut a) = entity.get_mut::() { a.0 -= 1; } @@ -4115,7 +4095,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(1))); assert_eq!(world.entity(b2).get(), Some(&B(2))); - for mut entity in world.iter_entities_mut() { + for mut entity in world.iter_all_entities_mut() { if let Some(mut b) = entity.get_mut::() { b.0 *= 2; } @@ -4125,7 +4105,7 @@ mod tests { assert_eq!(world.entity(b1).get(), Some(&B(2))); assert_eq!(world.entity(b2).get(), Some(&B(4))); - let mut entities = world.iter_entities_mut().collect::>(); + let mut entities = world.iter_all_entities_mut().collect::>(); entities.sort_by_key(|e| e.get::().map(|a| a.0).or(e.get::().map(|b| b.0))); let (a, b) = entities.split_at_mut(2); core::mem::swap( @@ -4152,14 +4132,13 @@ mod tests { let e2 = world.spawn_empty().id(); assert!(world.get_entity(e1).is_ok()); - assert!(world.get_entity([e1, e2]).is_ok()); - assert!(world - .get_entity(&[e1, e2] /* this is an array not a slice */) - .is_ok()); - assert!(world.get_entity(&vec![e1, e2][..]).is_ok()); - assert!(world - .get_entity(&EntityHashSet::from_iter([e1, e2])) - .is_ok()); + assert!(world.get_many_entities([e1, e2]).is_ok()); + assert_eq!( + world + .iter_entities(&EntityHashSet::from_iter([e1, e2])) + .count(), + 2 + ); world.entity_mut(e1).despawn(); @@ -4167,30 +4146,19 @@ mod tests { Err(e1), world.get_entity(e1).map(|_| {}).map_err(|e| e.entity) ); - assert_eq!( - Err(e1), - world.get_entity([e1, e2]).map(|_| {}).map_err(|e| e.entity) - ); - assert_eq!( - Err(e1), - world - .get_entity(&[e1, e2] /* this is an array not a slice */) - .map(|_| {}) - .map_err(|e| e.entity) - ); assert_eq!( Err(e1), world - .get_entity(&vec![e1, e2][..]) + .get_many_entities([e1, e2]) .map(|_| {}) .map_err(|e| e.entity) ); assert_eq!( - Err(e1), world - .get_entity(&EntityHashSet::from_iter([e1, e2])) - .map(|_| {}) - .map_err(|e| e.entity) + .iter_entities(&EntityHashSet::from_iter([e1, e2])) + .map(|e| e.id()) + .collect::(), + EntityHashSet::from_iter([e2]) ); } @@ -4202,33 +4170,18 @@ mod tests { let e2 = world.spawn_empty().id(); assert!(world.get_entity_mut(e1).is_ok()); - assert!(world.get_entity_mut([e1, e2]).is_ok()); - assert!(world - .get_entity_mut(&[e1, e2] /* this is an array not a slice */) - .is_ok()); - assert!(world.get_entity_mut(&vec![e1, e2][..]).is_ok()); - assert!(world - .get_entity_mut(&EntityHashSet::from_iter([e1, e2])) - .is_ok()); - - assert_eq!( - Err(EntityMutableFetchError::AliasedMutability(e1)), - world.get_entity_mut([e1, e2, e1]).map(|_| {}) - ); + assert!(world.get_many_entities_mut([e1, e2]).is_ok()); assert_eq!( - Err(EntityMutableFetchError::AliasedMutability(e1)), world - .get_entity_mut(&[e1, e2, e1] /* this is an array not a slice */) - .map(|_| {}) + .iter_entities_mut(&EntityHashSet::from_iter([e1, e2])) + .count(), + 2 ); + assert_eq!( Err(EntityMutableFetchError::AliasedMutability(e1)), - world.get_entity_mut(&vec![e1, e2, e1][..]).map(|_| {}) + world.get_many_entities_mut([e1, e2, e1]).map(|_| {}) ); - // Aliased mutability isn't allowed by HashSets - assert!(world - .get_entity_mut(&EntityHashSet::from_iter([e1, e2, e1])) - .is_ok()); world.entity_mut(e1).despawn(); @@ -4237,22 +4190,15 @@ mod tests { Err(EntityMutableFetchError::EntityDoesNotExist(e)) if e.entity == e1 )); assert!(matches!( - world.get_entity_mut([e1, e2]).map(|_| {}), - Err(EntityMutableFetchError::EntityDoesNotExist(e)) if e.entity == e1)); - assert!(matches!( - world - .get_entity_mut(&[e1, e2] /* this is an array not a slice */) - .map(|_| {}), + world.get_many_entities_mut([e1, e2]).map(|_| {}), Err(EntityMutableFetchError::EntityDoesNotExist(e)) if e.entity == e1)); - assert!(matches!( - world.get_entity_mut(&vec![e1, e2][..]).map(|_| {}), - Err(EntityMutableFetchError::EntityDoesNotExist(e)) if e.entity == e1, - )); - assert!(matches!( + assert_eq!( world - .get_entity_mut(&EntityHashSet::from_iter([e1, e2])) - .map(|_| {}), - Err(EntityMutableFetchError::EntityDoesNotExist(e)) if e.entity == e1)); + .iter_entities_mut(&EntityHashSet::from_iter([e1, e2])) + .map(|e| e.id()) + .collect::(), + EntityHashSet::from_iter([e2]) + ); } #[test] diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index f094906b1267b..d5ab4c30bf363 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -6,18 +6,24 @@ use crate::{ bundle::Bundles, change_detection::{MaybeLocation, MutUntyped, Ticks, TicksMut}, component::{ComponentId, ComponentTicks, Components, Mutable, StorageType, Tick, TickCells}, - entity::{Entities, Entity, EntityBorrow, EntityDoesNotExistError, EntityLocation}, + entity::{ + Entities, Entity, EntityBorrow, EntityLocation, EntitySet, EntitySetIterator, + TrustedEntityBorrow, UniqueEntityArray, UniqueEntityIter, + }, observer::Observers, prelude::Component, query::{DebugCheckedUnwrap, ReadOnlyQueryData}, removal_detection::RemovedComponentEvents, resource::Resource, storage::{ComponentSparseSet, Storages, Table}, - world::RawCommandQueue, + world::{error::EntityMutableFetchError, EntityDoesNotExistError, EntityMut, RawCommandQueue}, }; use bevy_platform_support::sync::atomic::Ordering; use bevy_ptr::{Ptr, UnsafeCellDeref}; -use core::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData, panic::Location, ptr}; +use core::{ + any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData, mem::MaybeUninit, + panic::Location, ptr, +}; use thiserror::Error; /// Variant of the [`World`] where resource and component accesses take `&self`, and the responsibility to avoid @@ -368,6 +374,74 @@ impl<'w> UnsafeWorldCell<'w> { Ok(UnsafeEntityCell::new(self, entity, location)) } + /// Shared implementation of [`World::get_many_entities_mut`] and [`DeferredWorld::get_many_entities_mut`](crate::world::DeferredWorld::get_many_entities_mut). + /// + /// # Safety + /// + /// The caller must have mutable access to all provided entities. + pub(crate) unsafe fn get_many_entities_mut( + self, + entities: [T; N], + ) -> Result<[EntityMut<'w>; N], EntityMutableFetchError> { + // Check for duplicate entities. + for i in 0..entities.len() { + for j in 0..i { + if entities[i] == entities[j] { + return Err(EntityMutableFetchError::AliasedMutability( + entities[i].entity(), + )); + } + } + } + + // SAFETY: We just checked for duplicates + let entities = unsafe { UniqueEntityArray::from_array_unchecked(entities) }; + // SAFETY: Caller ensures we have mutable access to these entities + Ok(self.get_many_entities_unique_mut(entities)?) + } + + /// Shared implementation of [`World::get_many_entities_unique_mut`] and [`DeferredWorld::get_many_entities_unique_mut`](crate::world::DeferredWorld::get_many_entities_unique_mut). + /// + /// # Safety + /// + /// The caller must have mutable access to all provided entities. + pub(crate) unsafe fn get_many_entities_unique_mut( + self, + entities: UniqueEntityArray, + ) -> Result<[EntityMut<'w>; N], EntityDoesNotExistError> { + let mut refs = [const { MaybeUninit::uninit() }; N]; + for (r, id) in core::iter::zip(&mut refs, entities) { + let ecell = self.get_entity(id.entity())?; + // SAFETY: `&mut self` gives read access to the entire world, and prevents mutable access. + // `UniqueEntityArray` ensures all entities are unique + *r = MaybeUninit::new(unsafe { EntityMut::new(ecell) }); + } + + // SAFETY: Each item was initialized in the loop above. + let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) }); + + Ok(refs) + } + + /// Shared implementation of [`World::iter_entities_mut`] and [`DeferredWorld::iter_entities_mut`](crate::world::DeferredWorld::iter_entities_mut). + /// + /// # Safety + /// + /// The caller must have mutable access to all provided entities. + pub(crate) unsafe fn iter_entities_mut( + self, + entities: impl EntitySet, + ) -> impl EntitySetIterator> { + let iter = entities + .into_iter() + .filter_map(move |e| self.get_entity(e.entity()).ok()) + // SAFETY: `&mut self` gives read access to the entire world, and prevents mutable access. + // `EntitySet` ensures that the entities are all unique. + .map(|ecell| unsafe { EntityMut::new(ecell) }); + // SAFETY: `EntitySet` ensures that `entities` are all unique, and each `EntityMut` corresponds to one of them + unsafe { UniqueEntityIter::from_iterator_unchecked(iter) } + } + /// Gets a reference to the resource of the given type if it exists /// /// # Safety diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index c3d26c05308ce..06bfea37bce3c 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -49,7 +49,7 @@ impl DynamicScene { /// Create a new dynamic scene from a given world. pub fn from_world(world: &World) -> Self { DynamicSceneBuilder::from_world(world) - .extract_entities(world.iter_entities().map(|entity| entity.id())) + .extract_entities(world.iter_all_entities().map(|entity| entity.id())) .extract_resources() .build() }