diff --git a/crates/bevy_ecs/src/entity/clone_entities.rs b/crates/bevy_ecs/src/entity/clone_entities.rs index 7b1884e54e5d1..e5a23e1417ab9 100644 --- a/crates/bevy_ecs/src/entity/clone_entities.rs +++ b/crates/bevy_ecs/src/entity/clone_entities.rs @@ -11,7 +11,7 @@ use crate::{ entity::{hash_map::EntityHashMap, Entity, EntityAllocator, EntityMapper}, query::DebugCheckedUnwrap, relationship::RelationshipHookMode, - world::World, + world::{All, World}, }; use alloc::{boxed::Box, collections::VecDeque, vec::Vec}; use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet}; @@ -633,8 +633,11 @@ impl EntityCloner { // SAFETY: // - There are no other mutable references to source entity. // - `component` is from `source_entity`'s archetype - let source_component_ptr = - unsafe { source_entity.get_by_id(component).debug_checked_unwrap() }; + let source_component_ptr = unsafe { + source_entity + .get_by_id(All, component) + .debug_checked_unwrap() + }; let source_component = SourceComponent { info, diff --git a/crates/bevy_ecs/src/observer/runner.rs b/crates/bevy_ecs/src/observer/runner.rs index dfffe3bec60cd..37c2219369c10 100644 --- a/crates/bevy_ecs/src/observer/runner.rs +++ b/crates/bevy_ecs/src/observer/runner.rs @@ -9,7 +9,7 @@ use crate::{ prelude::*, query::DebugCheckedUnwrap, system::{ObserverSystem, RunSystemError}, - world::DeferredWorld, + world::{All, DeferredWorld}, }; use bevy_ptr::PtrMut; @@ -44,7 +44,11 @@ pub(super) unsafe fn observer_system_runner().debug_checked_unwrap() }; + let mut state = unsafe { + observer_cell + .get_mut::(All) + .debug_checked_unwrap() + }; // TODO: Move this check into the observer cache to avoid dynamic dispatch let last_trigger = world.last_trigger_id(); diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index d0b191513e8ed..547325e0b8a7f 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -10,8 +10,8 @@ use crate::{ }, storage::{ComponentSparseSet, Table, TableRow}, world::{ - unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityMutExcept, EntityRef, EntityRefExcept, - FilteredEntityMut, FilteredEntityRef, Mut, Ref, World, + unsafe_world_cell::UnsafeWorldCell, All, EntityMut, EntityMutExcept, EntityRef, + EntityRefExcept, Except, Filtered, FilteredEntityMut, FilteredEntityRef, Mut, Ref, World, }, }; use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref}; @@ -366,10 +366,11 @@ pub type ROQueryItem<'w, 's, D> = QueryItem<'w, 's, ::ReadOnly>; /// A [`QueryData`] that does not borrow from its [`QueryState`](crate::query::QueryState). /// -/// This is implemented by most `QueryData` types. -/// The main exceptions are [`FilteredEntityRef`], [`FilteredEntityMut`], [`EntityRefExcept`], and [`EntityMutExcept`], -/// which borrow an access list from their query state. -/// Consider using a full [`EntityRef`] or [`EntityMut`] if you would need those. +/// This is implemented by most `QueryData` types. The main exceptions are +/// [`FilteredEntityRef`], [`FilteredEntityMut`], [`EntityRefExcept`], and +/// [`EntityMutExcept`], which borrow an access list from their query state. +/// Consider using a full [`EntityRef`] or [`EntityMut`] if you would +/// need those. pub trait ReleaseStateQueryData: QueryData { /// Releases the borrow from the query state by converting an item to have a `'static` state lifetime. fn release_state<'w>(item: Self::Item<'w, '_>) -> Self::Item<'w, 'static>; @@ -856,7 +857,7 @@ unsafe impl<'a> QueryData for EntityRef<'a> { .debug_checked_unwrap() }; // SAFETY: Read-only access to every component has been registered. - Some(unsafe { EntityRef::new(cell) }) + Some(unsafe { EntityRef::new(cell, All) }) } fn iter_access(_state: &Self::State) -> impl Iterator> { @@ -966,7 +967,7 @@ unsafe impl<'a> QueryData for EntityMut<'a> { .debug_checked_unwrap() }; // SAFETY: mutable access to every component has been registered. - Some(unsafe { EntityMut::new(cell) }) + Some(unsafe { EntityMut::new(cell, All) }) } fn iter_access(_state: &Self::State) -> impl Iterator> { @@ -1093,8 +1094,8 @@ unsafe impl<'a, 'b> QueryData for FilteredEntityRef<'a, 'b> { .get_entity_with_ticks(entity, fetch.last_run, fetch.this_run) .debug_checked_unwrap() }; - // SAFETY: mutable access to every component has been registered. - Some(unsafe { FilteredEntityRef::new(cell, access) }) + // SAFETY: read-only access to the components in `access` has been registered. + Some(unsafe { EntityRef::new(cell, Filtered(access)) }) } fn iter_access(state: &Self::State) -> impl Iterator> { @@ -1216,8 +1217,8 @@ unsafe impl<'a, 'b> QueryData for FilteredEntityMut<'a, 'b> { .get_entity_with_ticks(entity, fetch.last_run, fetch.this_run) .debug_checked_unwrap() }; - // SAFETY: mutable access to every component has been registered. - Some(unsafe { FilteredEntityMut::new(cell, access) }) + // SAFETY: mutable access to the components in `access` has been registered. + Some(unsafe { EntityMut::new(cell, Filtered(access)) }) } fn iter_access(state: &Self::State) -> impl Iterator> { @@ -1331,7 +1332,8 @@ where .world .get_entity_with_ticks(entity, fetch.last_run, fetch.this_run) .unwrap(); - Some(EntityRefExcept::new(cell, access)) + // SAFETY: `access` was constructed based on the components in `B`, and read-only access registered. + Some(unsafe { EntityRef::new(cell, Except::new(access)) }) } fn iter_access(state: &Self::State) -> impl Iterator> { @@ -1450,7 +1452,8 @@ where .world .get_entity_with_ticks(entity, fetch.last_run, fetch.this_run) .unwrap(); - Some(EntityMutExcept::new(cell, access)) + // SAFETY: `access` was constructed based on the components in `B`, and mutable access registered. + Some(unsafe { EntityMut::new(cell, Except::new(access)) }) } fn iter_access(state: &Self::State) -> impl Iterator> { diff --git a/crates/bevy_ecs/src/reflect/component.rs b/crates/bevy_ecs/src/reflect/component.rs index c38deeb31683c..df0f733106365 100644 --- a/crates/bevy_ecs/src/reflect/component.rs +++ b/crates/bevy_ecs/src/reflect/component.rs @@ -65,7 +65,7 @@ use crate::{ prelude::Component, relationship::RelationshipHookMode, world::{ - unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut, + unsafe_world_cell::UnsafeEntityCell, All, EntityMut, EntityWorldMut, FilteredEntityMut, FilteredEntityRef, World, }, }; @@ -383,7 +383,7 @@ impl FromType for ReflectComponent { // SAFETY: reflect_unchecked_mut is an unsafe function pointer used by // `reflect_unchecked_mut` which must be called with an UnsafeEntityCell with access to the component `C` on the `entity` // guard ensures `C` is a mutable component - let c = unsafe { entity.get_mut_assume_mutable::() }; + let c = unsafe { entity.get_mut_assume_mutable::(All) }; c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect)) }, register_component: |world: &mut World| -> ComponentId { diff --git a/crates/bevy_ecs/src/world/entity_access/all.rs b/crates/bevy_ecs/src/world/entity_access/all.rs new file mode 100644 index 0000000000000..ee4faa9ed25b4 --- /dev/null +++ b/crates/bevy_ecs/src/world/entity_access/all.rs @@ -0,0 +1,260 @@ +use crate::{ + query::{has_conflicts, Access, QueryAccessError, ReadOnlyQueryData, ReleaseStateQueryData}, + world::{All, EntityMut, EntityRef, Filtered, FilteredEntityMut, FilteredEntityRef}, +}; + +impl<'w> EntityRef<'w, All> { + /// Consumes `self` and returns a [`FilteredEntityRef`] with read access to + /// all components. + pub fn into_filtered(self) -> FilteredEntityRef<'w, 'static> { + // SAFETY: + // - `Access:new_read_all` equals the read permissions of `self`'s `All` access. + unsafe { EntityRef::new(self.cell, Filtered(const { &Access::new_read_all() })) } + } + + /// Returns read-only components for the current entity that match the query `Q`. + /// + /// # Panics + /// + /// If the entity does not have the components required by the query `Q`. + pub fn components(&self) -> Q::Item<'w, 'static> { + self.get_components::() + .expect("Query does not match the current entity") + } + + /// Returns read-only components for the current entity that match the query `Q`, + /// or `None` if the entity does not have the components required by the query `Q`. + pub fn get_components( + &self, + ) -> Result, QueryAccessError> { + // SAFETY: + // - We have read-only access to all components of this entity. + // - The query is read-only, and read-only references cannot have conflicts. + unsafe { self.cell.get_components::() } + } +} + +impl<'w> From> for FilteredEntityRef<'w, 'static> { + #[inline] + fn from(entity: EntityRef<'w, All>) -> Self { + entity.into_filtered() + } +} + +impl<'w> From<&EntityRef<'w, All>> for FilteredEntityRef<'w, 'static> { + #[inline] + fn from(entity: &EntityRef<'w, All>) -> Self { + entity.into_filtered() + } +} + +impl<'w> EntityMut<'w, All> { + /// Consumes `self` and returns a [`FilteredEntityMut`] with read and write + /// access to all components. + #[inline] + pub fn into_filtered(self) -> FilteredEntityMut<'w, 'static> { + // SAFETY: + // - `Access::new_write_all` equals the read and write permissions of `entity`'s `All` access. + // - Consuming `self` ensures there are no other accesses. + unsafe { EntityMut::new(self.cell, Filtered(const { &Access::new_write_all() })) } + } + + /// Returns read-only components for the current entity that match the query `Q`. + /// + /// # Panics + /// + /// If the entity does not have the components required by the query `Q`. + pub fn components(&self) -> Q::Item<'_, 'static> { + self.as_readonly().components::() + } + + /// Returns read-only components for the current entity that match the query `Q`, + /// or `None` if the entity does not have the components required by the query `Q`. + pub fn get_components( + &self, + ) -> Result, QueryAccessError> { + self.as_readonly().get_components::() + } + + /// Returns components for the current entity that match the query `Q`. + /// In the case of conflicting [`QueryData`](crate::query::QueryData), unregistered components, or missing components, + /// this will return a [`QueryAccessError`] + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// #[derive(Component)] + /// struct X(usize); + /// #[derive(Component)] + /// struct Y(usize); + /// + /// # let mut world = World::default(); + /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); + /// // Get mutable access to two components at once + /// // SAFETY: X and Y are different components + /// let (mut x, mut y) = entity.get_components_mut::<(&mut X, &mut Y)>().unwrap(); + /// ``` + /// + /// Note that this does a O(n^2) check that the [`QueryData`](crate::query::QueryData) does not conflict. If performance is a + /// consideration you should use [`Self::get_components_mut_unchecked`] instead. + pub fn get_components_mut( + &mut self, + ) -> Result, QueryAccessError> { + self.reborrow().into_components_mut::() + } + + /// Returns components for the current entity that match the query `Q`, + /// or `None` if the entity does not have the components required by the query `Q`. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// #[derive(Component)] + /// struct X(usize); + /// #[derive(Component)] + /// struct Y(usize); + /// + /// # let mut world = World::default(); + /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); + /// // Get mutable access to two components at once + /// // SAFETY: X and Y are different components + /// let (mut x, mut y) = + /// unsafe { entity.get_components_mut_unchecked::<(&mut X, &mut Y)>() }.unwrap(); + /// *x = X(1); + /// *y = Y(1); + /// // This would trigger undefined behavior, as the `&mut X`s would alias: + /// // entity.get_components_mut_unchecked::<(&mut X, &mut X)>(); + /// ``` + /// + /// # Safety + /// It is the caller's responsibility to ensure that + /// the `QueryData` does not provide aliasing mutable references to the same component. + pub unsafe fn get_components_mut_unchecked( + &mut self, + ) -> Result, QueryAccessError> { + // SAFETY: Caller the `QueryData` does not provide aliasing mutable references to the same component + unsafe { self.reborrow().into_components_mut_unchecked::() } + } + + /// Consumes self and returns components for the current entity that match the query `Q` for the world lifetime `'w`, + /// or `None` if the entity does not have the components required by the query `Q`. + /// + /// The checks for aliasing mutable references may be expensive. + /// If performance is a concern, consider making multiple calls to [`Self::get_mut`]. + /// If that is not possible, consider using [`Self::into_components_mut_unchecked`] to skip the checks. + /// + /// # Panics + /// + /// If the `QueryData` provides aliasing mutable references to the same component. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// #[derive(Component)] + /// struct X(usize); + /// #[derive(Component)] + /// struct Y(usize); + /// + /// # let mut world = World::default(); + /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); + /// // Get mutable access to two components at once + /// let (mut x, mut y) = entity.into_components_mut::<(&mut X, &mut Y)>().unwrap(); + /// *x = X(1); + /// *y = Y(1); + /// ``` + /// + /// ```should_panic + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Component)] + /// # struct X(usize); + /// # + /// # let mut world = World::default(); + /// let mut entity = world.spawn((X(0))).into_mutable(); + /// // This panics, as the `&mut X`s would alias: + /// entity.into_components_mut::<(&mut X, &mut X)>(); + /// ``` + pub fn into_components_mut( + self, + ) -> Result, QueryAccessError> { + has_conflicts::(self.cell.world().components())?; + + // SAFETY: we checked that there were not conflicting components above + unsafe { self.into_components_mut_unchecked::() } + } + + /// Consumes self and returns components for the current entity that match the query `Q` for the world lifetime `'w`, + /// or `None` if the entity does not have the components required by the query `Q`. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// #[derive(Component)] + /// struct X(usize); + /// #[derive(Component)] + /// struct Y(usize); + /// + /// # let mut world = World::default(); + /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); + /// // Get mutable access to two components at once + /// // SAFETY: X and Y are different components + /// let (mut x, mut y) = + /// unsafe { entity.into_components_mut_unchecked::<(&mut X, &mut Y)>() }.unwrap(); + /// *x = X(1); + /// *y = Y(1); + /// // This would trigger undefined behavior, as the `&mut X`s would alias: + /// // entity.into_components_mut_unchecked::<(&mut X, &mut X)>(); + /// ``` + /// + /// # Safety + /// It is the caller's responsibility to ensure that + /// the `QueryData` does not provide aliasing mutable references to the same component. + /// + /// # See also + /// + /// - [`Self::into_components_mut`] for the safe version that performs aliasing checks + pub unsafe fn into_components_mut_unchecked( + self, + ) -> Result, QueryAccessError> { + // SAFETY: + // - We have mutable access to all components of this entity. + // - Caller asserts the `QueryData` does not provide aliasing mutable references to the same component + unsafe { self.cell.get_components::() } + } +} + +impl<'w> From> for FilteredEntityRef<'w, 'static> { + #[inline] + fn from(entity: EntityMut<'w, All>) -> Self { + entity.into_readonly().into_filtered() + } +} + +impl<'w> From<&'w EntityMut<'_, All>> for FilteredEntityRef<'w, 'static> { + #[inline] + fn from(entity: &'w EntityMut<'_, All>) -> Self { + entity.as_readonly().into_filtered() + } +} + +impl<'w> From> for FilteredEntityMut<'w, 'static> { + #[inline] + fn from(entity: EntityMut<'w, All>) -> Self { + entity.into_filtered() + } +} + +impl<'w> From<&'w mut EntityMut<'_, All>> for FilteredEntityMut<'w, 'static> { + #[inline] + fn from(entity: &'w mut EntityMut<'_, All>) -> Self { + entity.reborrow().into_filtered() + } +} diff --git a/crates/bevy_ecs/src/world/entity_access/as_access.rs b/crates/bevy_ecs/src/world/entity_access/as_access.rs new file mode 100644 index 0000000000000..1aef14e97c8ea --- /dev/null +++ b/crates/bevy_ecs/src/world/entity_access/as_access.rs @@ -0,0 +1,188 @@ +use core::{marker::PhantomData, ops::Deref}; + +use crate::{bundle::Bundle, query::Access}; + +/// Defines the set of [`Component`]s accessible by the entity reference types +/// [`EntityRef`] and [`EntityMut`]. +/// +/// The following accesses are provided: +/// - [`All`]: Provides access to all components. This is the default access. +/// - [`Filtered`]: Provides access only to the components specified in an +/// [`Access`]. This is used by [`FilteredEntityRef`] and [`FilteredEntityMut`]. +/// - [`Except`]: Provides access to all components except those in a specified +/// [`Bundle`]. This is used by [`EntityRefExcept`] and [`EntityMutExcept`]. +/// +/// [`Component`]: crate::component::Component +/// [`EntityRef`]: crate::world::EntityRef +/// [`EntityMut`]: crate::world::EntityMut +/// [`FilteredEntityRef`]: crate::world::FilteredEntityRef +/// [`FilteredEntityMut`]: crate::world::FilteredEntityMut +/// [`EntityRefExcept`]: crate::world::EntityRefExcept +/// [`EntityMutExcept`]: crate::world::EntityMutExcept +pub trait AsAccess: Copy + Deref {} + +/// [`AsAccess`] that provides access to all of an entity's components. This +/// is the default access of [`EntityRef`] and [`EntityMut`]. +/// +/// [`EntityRef`]: crate::world::EntityRef +/// [`EntityMut`]: crate::world::EntityMut +#[derive(Clone, Copy)] +pub struct All; + +impl AsAccess for All {} + +impl Deref for All { + type Target = Access; + + fn deref(&self) -> &Access { + const { &Access::new_write_all() } + } +} + +/// [`AsAccess`] that provides access to only the components specified in the +/// provided [`Access`]. [`FilteredEntityRef`] and [`FilteredEntityMut`] use +/// this access. +/// +/// [`FilteredEntityRef`]: crate::world::FilteredEntityRef +/// [`FilteredEntityMut`]: crate::world::FilteredEntityMut +#[derive(Clone, Copy)] +pub struct Filtered<'s>(pub &'s Access); + +impl AsAccess for Filtered<'_> {} + +impl<'s, B: Bundle> From> for Filtered<'s> { + fn from(value: Except<'s, B>) -> Self { + // SAFETY: We're not discarding the `Except` semantics as long as the + // `Access` matched the `Bundle` `B`. + Filtered(value.0) + } +} + +impl Deref for Filtered<'_> { + type Target = Access; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +/// [`AsAccess`] that provides access to all components except those in the +/// provided [`Bundle`] `B`. [`EntityRefExcept`] and [`EntityMutExcept`] use +/// this access. +/// +/// [`EntityRefExcept`]: crate::world::EntityRefExcept +/// [`EntityMutExcept`]: crate::world::EntityMutExcept +pub struct Except<'s, B: Bundle>(pub &'s Access, PhantomData); + +impl<'s, B: Bundle> Except<'s, B> { + /// Creates a new `Except` access from the given [`Access`]. + /// + /// # Safety + /// + /// The provided `Access` must accurately reflect the components in `B`. + pub unsafe fn new(access: &'s Access) -> Self { + Except(access, PhantomData) + } +} + +impl<'s, B: Bundle> Copy for Except<'s, B> {} + +impl<'s, B: Bundle> Clone for Except<'s, B> { + fn clone(&self) -> Self { + *self + } +} + +impl AsAccess for Except<'_, B> {} + +impl Deref for Except<'_, B> { + type Target = Access; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +#[cfg(test)] +mod tests { + use bevy_ecs_macros::Component; + + use crate::{ + query::Access, + world::{Except, World}, + }; + + #[derive(Component)] + pub struct TestComponent; + + #[test] + fn all() { + let mut world = World::new(); + + let c1 = world.register_component::>(); + let c2 = world.register_component::>(); + let c3 = world.register_component::>(); + + let all = super::All; + + assert!(all.has_component_read(c1)); + assert!(all.has_component_write(c1)); + + assert!(all.has_component_read(c2)); + assert!(all.has_component_write(c2)); + + assert!(all.has_component_read(c3)); + assert!(all.has_component_write(c3)); + } + + #[test] + fn filtered() { + let mut world = World::new(); + + let c1 = world.register_component::>(); + let c2 = world.register_component::>(); + let c3 = world.register_component::>(); + + let mut access = Access::new(); + access.add_component_read(c1); + access.add_component_write(c2); + + let filtered = super::Filtered(&access); + + assert!(filtered.has_component_read(c1)); + assert!(!filtered.has_component_write(c1)); + + assert!(filtered.has_component_read(c2)); + assert!(filtered.has_component_write(c2)); + + assert!(!filtered.has_component_read(c3)); + assert!(!filtered.has_component_write(c3)); + } + + #[test] + fn except() { + let mut world = World::new(); + + let c1 = world.register_component::>(); + let c2 = world.register_component::>(); + let c3 = world.register_component::>(); + + let mut access = Access::new_write_all(); + access.remove_component_read(c1); + access.remove_component_write(c1); + access.remove_component_read(c2); + access.remove_component_write(c2); + + // SAFETY: The `Access` accurately reflects the excluded components. + let except = unsafe { Except::<(TestComponent<1>, TestComponent<2>)>::new(&access) }; + + assert!(!except.has_component_read(c1)); + assert!(!except.has_component_write(c1)); + + assert!(!except.has_component_read(c2)); + assert!(!except.has_component_write(c2)); + + assert!(except.has_component_read(c3)); + assert!(except.has_component_write(c3)); + } +} diff --git a/crates/bevy_ecs/src/world/entity_access/component_fetch.rs b/crates/bevy_ecs/src/world/entity_access/component_fetch.rs index 18dce1d725708..383ca108d8ed5 100644 --- a/crates/bevy_ecs/src/world/entity_access/component_fetch.rs +++ b/crates/bevy_ecs/src/world/entity_access/component_fetch.rs @@ -1,7 +1,7 @@ use crate::{ change_detection::MutUntyped, component::ComponentId, - world::{error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell}, + world::{error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, AsAccess}, }; use alloc::vec::Vec; @@ -44,9 +44,9 @@ pub unsafe trait DynamicComponentFetch { /// /// # Safety /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeEntityCell`] has read-only access to the fetched components. - /// - No other mutable references to the fetched components exist at the same time. + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `cell` in a way that would violate Rust's aliasing rules, + /// including via copies of `cell` or other indirect means. /// /// # Errors /// @@ -54,6 +54,7 @@ pub unsafe trait DynamicComponentFetch { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError>; /// Returns untyped mutable reference(s) to the component(s) with the @@ -61,9 +62,9 @@ pub unsafe trait DynamicComponentFetch { /// /// # Safety /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeEntityCell`] has mutable access to the fetched components. - /// - No other references to the fetched components exist at the same time. + /// Caller must ensure the provided [`AsAccess`] does not exceed the write + /// permissions of `cell` in a way that would violate Rust's aliasing rules, + /// including via copies of `cell` or other indirect means. /// /// # Errors /// @@ -72,6 +73,7 @@ pub unsafe trait DynamicComponentFetch { unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError>; /// Returns untyped mutable reference(s) to the component(s) with the @@ -80,9 +82,10 @@ pub unsafe trait DynamicComponentFetch { /// /// # Safety /// - /// It is the caller's responsibility to ensure that: - /// - The given [`UnsafeEntityCell`] has mutable access to the fetched components. - /// - No other references to the fetched components exist at the same time. + /// Caller must ensure that: + /// - The provided [`AsAccess`] does not exceed the write permissions of + /// `cell` in a way that would violate Rust's aliasing rules, including + /// via copies of `cell` or other indirect means. /// - The requested components are all mutable. /// /// # Errors @@ -92,6 +95,7 @@ pub unsafe trait DynamicComponentFetch { unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError>; } @@ -105,26 +109,29 @@ unsafe impl DynamicComponentFetch for ComponentId { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // SAFETY: caller ensures that the cell has read access to the component. - unsafe { cell.get_by_id(self) }.ok_or(EntityComponentError::MissingComponent(self)) + unsafe { cell.get_by_id(access, self) }.ok_or(EntityComponentError::MissingComponent(self)) } unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_by_id(self) } + unsafe { cell.get_mut_by_id(access, self) } .map_err(|_| EntityComponentError::MissingComponent(self)) } unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_assume_mutable_by_id(self) } + unsafe { cell.get_mut_assume_mutable_by_id(access, self) } .map_err(|_| EntityComponentError::MissingComponent(self)) } } @@ -139,25 +146,25 @@ unsafe impl DynamicComponentFetch for [ComponentId; N] { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { - // SAFETY: Uphelp by caller. - unsafe { <&Self>::fetch_ref(&self, cell) } + <&Self>::fetch_ref(&self, cell, access) } unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { - // SAFETY: Uphelp by caller. - unsafe { <&Self>::fetch_mut(&self, cell) } + <&Self>::fetch_mut(&self, cell, access) } unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { - // SAFETY: Uphelp by caller. - unsafe { <&Self>::fetch_mut_assume_mutable(&self, cell) } + <&Self>::fetch_mut_assume_mutable(&self, cell, access) } } @@ -171,12 +178,14 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId; N] { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { let mut ptrs = [const { MaybeUninit::uninit() }; N]; for (ptr, &id) in core::iter::zip(&mut ptrs, self) { *ptr = MaybeUninit::new( // SAFETY: caller ensures that the cell has read access to the component. - unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?, + unsafe { cell.get_by_id(access, id) } + .ok_or(EntityComponentError::MissingComponent(id))?, ); } @@ -189,6 +198,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId; N] { unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // Check for duplicate component IDs. for i in 0..self.len() { @@ -203,7 +213,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId; N] { for (ptr, &id) in core::iter::zip(&mut ptrs, self) { *ptr = MaybeUninit::new( // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_by_id(id) } + unsafe { cell.get_mut_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } @@ -217,6 +227,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId; N] { unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // Check for duplicate component IDs. for i in 0..self.len() { @@ -231,7 +242,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId; N] { for (ptr, &id) in core::iter::zip(&mut ptrs, self) { *ptr = MaybeUninit::new( // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_assume_mutable_by_id(id) } + unsafe { cell.get_mut_assume_mutable_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } @@ -253,12 +264,14 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId] { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { let mut ptrs = Vec::with_capacity(self.len()); for &id in self { ptrs.push( // SAFETY: caller ensures that the cell has read access to the component. - unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?, + unsafe { cell.get_by_id(access, id) } + .ok_or(EntityComponentError::MissingComponent(id))?, ); } Ok(ptrs) @@ -267,6 +280,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId] { unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // Check for duplicate component IDs. for i in 0..self.len() { @@ -281,7 +295,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId] { for &id in self { ptrs.push( // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_by_id(id) } + unsafe { cell.get_mut_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } @@ -291,6 +305,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId] { unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { // Check for duplicate component IDs. for i in 0..self.len() { @@ -305,7 +320,7 @@ unsafe impl DynamicComponentFetch for &'_ [ComponentId] { for &id in self { ptrs.push( // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_assume_mutable_by_id(id) } + unsafe { cell.get_mut_assume_mutable_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } @@ -323,13 +338,15 @@ unsafe impl DynamicComponentFetch for &'_ HashSet { unsafe fn fetch_ref( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default()); for &id in self { ptrs.insert( id, // SAFETY: caller ensures that the cell has read access to the component. - unsafe { cell.get_by_id(id) }.ok_or(EntityComponentError::MissingComponent(id))?, + unsafe { cell.get_by_id(access, id) } + .ok_or(EntityComponentError::MissingComponent(id))?, ); } Ok(ptrs) @@ -338,13 +355,14 @@ unsafe impl DynamicComponentFetch for &'_ HashSet { unsafe fn fetch_mut( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default()); for &id in self { ptrs.insert( id, // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_by_id(id) } + unsafe { cell.get_mut_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } @@ -354,13 +372,14 @@ unsafe impl DynamicComponentFetch for &'_ HashSet { unsafe fn fetch_mut_assume_mutable( self, cell: UnsafeEntityCell<'_>, + access: impl AsAccess, ) -> Result, EntityComponentError> { let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default()); for &id in self { ptrs.insert( id, // SAFETY: caller ensures that the cell has mutable access to the component. - unsafe { cell.get_mut_assume_mutable_by_id(id) } + unsafe { cell.get_mut_assume_mutable_by_id(access, id) } .map_err(|_| EntityComponentError::MissingComponent(id))?, ); } diff --git a/crates/bevy_ecs/src/world/entity_access/entity_mut.rs b/crates/bevy_ecs/src/world/entity_access/entity_mut.rs index 1be7c3dd9962c..5f4b8320a5ed9 100644 --- a/crates/bevy_ecs/src/world/entity_access/entity_mut.rs +++ b/crates/bevy_ecs/src/world/entity_access/entity_mut.rs @@ -3,10 +3,9 @@ use crate::{ change_detection::{ComponentTicks, MaybeLocation, Tick}, component::{Component, ComponentId, Mutable}, entity::{ContainsEntity, Entity, EntityEquivalent, EntityLocation}, - query::{has_conflicts, Access, QueryAccessError, ReadOnlyQueryData, ReleaseStateQueryData}, world::{ - error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, DynamicComponentFetch, - EntityRef, FilteredEntityMut, FilteredEntityRef, Mut, Ref, + error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, All, AsAccess, + DynamicComponentFetch, EntityRef, Mut, Ref, }, }; @@ -16,12 +15,23 @@ use core::{ hash::{Hash, Hasher}, }; -/// Provides mutable access to a single entity and all of its components. +/// Provides mutable access to a single [`Entity`] and the components allowed by +/// the [`AsAccess`] `A`. Plain `EntityMut`s have an [`AsAccess`] +/// of [`All`], providing access to all components of the entity. /// /// Contrast with [`EntityWorldMut`], which allows adding and removing components, /// despawning the entity, and provides mutable access to the entire world. /// Because of this, `EntityWorldMut` cannot coexist with any other world accesses. /// +/// # [`AsAccess`]s +/// +/// Access kinds describe what you can access on an `EntityMut`. The default +/// kind is [`All`], which provides access to all components of the entity. +/// Other kinds, such as [`Filtered`] and [`Except`], can restrict access to +/// only a subset of components. +/// +/// See the documentation of [`AsAccess`] for more details. +/// /// # Examples /// /// Disjoint mutable access. @@ -39,57 +49,51 @@ use core::{ /// ``` /// /// [`EntityWorldMut`]: crate::world::EntityWorldMut -pub struct EntityMut<'w> { - cell: UnsafeEntityCell<'w>, +/// [`Filtered`]: crate::world::Filtered +/// [`Except`]: crate::world::Except +pub struct EntityMut<'w, A: AsAccess = All> { + pub(super) cell: UnsafeEntityCell<'w>, + access: A, } -impl<'w> EntityMut<'w> { +impl<'w, A: AsAccess> EntityMut<'w, A> { /// # Safety - /// - `cell` must have permission to mutate every component of the entity. - /// - No accesses to any of the entity's components may exist - /// at the same time as the returned [`EntityMut`]. + /// + /// Caller must ensure `access` does not exceed the read or write permissions + /// of `cell` in a way that would violate Rust's aliasing rules, including + /// simultaneous access of `cell` via another `EntityMut`, `EntityRef`, or + /// any other means. #[inline] - pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self { - Self { cell } + pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>, access: A) -> Self { + Self { cell, access } } /// Returns a new instance with a shorter lifetime. /// This is useful if you have `&mut EntityMut`, but you need `EntityMut`. #[inline] - pub fn reborrow(&mut self) -> EntityMut<'_> { - // SAFETY: - // - We have exclusive access to the entire entity and its components. - // - `&mut self` ensures there are no other accesses. - unsafe { Self::new(self.cell) } - } - - /// Consumes `self` and returns read-only access to all of the entity's - /// components, with the world `'w` lifetime. - #[inline] - pub fn into_readonly(self) -> EntityRef<'w> { - // SAFETY: - // - We have exclusive access to the entire entity and its components. - // - Consuming `self` ensures there are no other accesses. - unsafe { EntityRef::new(self.cell) } + pub fn reborrow(&mut self) -> EntityMut<'_, A> { + // SAFETY: We have exclusive access to the entire entity and its components. + unsafe { EntityMut::new(self.cell, self.access) } } - /// Gets read-only access to all of the entity's components. + /// Consumes `self` and returns a [`EntityRef`] with the same access + /// permissions. #[inline] - pub fn as_readonly(&self) -> EntityRef<'_> { + pub fn into_readonly(self) -> EntityRef<'w, A> { // SAFETY: - // - We have exclusive access to the entire entity and its components. - // - `&self` ensures there are no mutable accesses. - unsafe { EntityRef::new(self.cell) } + // - Read permissions of `entity.access` are preserved. + // - Consuming `entity` ensures there are no mutable accesses. + unsafe { EntityRef::new(self.cell, self.access) } } - /// Consumes `self` and returns a [`FilteredEntityMut`] which has mutable - /// access to all of the entity's components, with the world `'w` lifetime. + /// Borrows `self` and returns a [`EntityRef`] with the same access + /// permissions. #[inline] - pub fn into_filtered(self) -> FilteredEntityMut<'w, 'static> { + pub fn as_readonly(&self) -> EntityRef<'_, A> { // SAFETY: - // - We have exclusive access to the entire entity and its components. - // - Consuming `self` ensures there are no other accesses. - unsafe { FilteredEntityMut::new(self.cell, const { &Access::new_write_all() }) } + // - Read permissions of `&entity.access` are preserved. + // - `&entity` ensures there are no mutable accesses. + unsafe { EntityRef::new(self.cell, self.access) } } /// Get access to the underlying [`UnsafeEntityCell`]. @@ -98,6 +102,12 @@ impl<'w> EntityMut<'w> { self.cell } + /// Returns a copy of the current [`AsAccess`]. + #[inline] + pub fn access(&self) -> A { + self.access + } + /// Returns the [ID](Entity) of the current entity. #[inline] #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] @@ -161,181 +171,6 @@ impl<'w> EntityMut<'w> { self.as_readonly().get() } - /// Returns read-only components for the current entity that match the query `Q`. - /// - /// # Panics - /// - /// If the entity does not have the components required by the query `Q`. - pub fn components(&self) -> Q::Item<'_, 'static> { - self.as_readonly().components::() - } - - /// Returns read-only components for the current entity that match the query `Q`, - /// or `None` if the entity does not have the components required by the query `Q`. - pub fn get_components( - &self, - ) -> Result, QueryAccessError> { - self.as_readonly().get_components::() - } - - /// Returns components for the current entity that match the query `Q`, - /// or `None` if the entity does not have the components required by the query `Q`. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// #[derive(Component)] - /// struct X(usize); - /// #[derive(Component)] - /// struct Y(usize); - /// - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); - /// // Get mutable access to two components at once - /// // SAFETY: X and Y are different components - /// let (mut x, mut y) = - /// unsafe { entity.get_components_mut_unchecked::<(&mut X, &mut Y)>() }.unwrap(); - /// *x = X(1); - /// *y = Y(1); - /// // This would trigger undefined behavior, as the `&mut X`s would alias: - /// // entity.get_components_mut_unchecked::<(&mut X, &mut X)>(); - /// ``` - /// - /// # Safety - /// It is the caller's responsibility to ensure that - /// the `QueryData` does not provide aliasing mutable references to the same component. - /// - /// # See also - /// - /// - [`Self::get_components_mut`] for the safe version that performs aliasing checks - pub unsafe fn get_components_mut_unchecked( - &mut self, - ) -> Result, QueryAccessError> { - // SAFETY: Caller ensures the `QueryData` does not provide aliasing mutable references to the same component - unsafe { self.reborrow().into_components_mut_unchecked::() } - } - - /// Returns components for the current entity that match the query `Q`. - /// In the case of conflicting [`QueryData`](crate::query::QueryData), unregistered components, or missing components, - /// this will return a [`QueryAccessError`] - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// #[derive(Component)] - /// struct X(usize); - /// #[derive(Component)] - /// struct Y(usize); - /// - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); - /// // Get mutable access to two components at once - /// // SAFETY: X and Y are different components - /// let (mut x, mut y) = entity.get_components_mut::<(&mut X, &mut Y)>().unwrap(); - /// ``` - /// - /// Note that this does a O(n^2) check that the [`QueryData`](crate::query::QueryData) does not conflict. If performance is a - /// consideration you should use [`Self::get_components_mut_unchecked`] instead. - pub fn get_components_mut( - &mut self, - ) -> Result, QueryAccessError> { - self.reborrow().into_components_mut::() - } - - /// Consumes self and returns components for the current entity that match the query `Q` for the world lifetime `'w`, - /// or `None` if the entity does not have the components required by the query `Q`. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// #[derive(Component)] - /// struct X(usize); - /// #[derive(Component)] - /// struct Y(usize); - /// - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); - /// // Get mutable access to two components at once - /// // SAFETY: X and Y are different components - /// let (mut x, mut y) = - /// unsafe { entity.into_components_mut_unchecked::<(&mut X, &mut Y)>() }.unwrap(); - /// *x = X(1); - /// *y = Y(1); - /// // This would trigger undefined behavior, as the `&mut X`s would alias: - /// // entity.into_components_mut_unchecked::<(&mut X, &mut X)>(); - /// ``` - /// - /// # Safety - /// It is the caller's responsibility to ensure that - /// the `QueryData` does not provide aliasing mutable references to the same component. - /// - /// # See also - /// - /// - [`Self::into_components_mut`] for the safe version that performs aliasing checks - pub unsafe fn into_components_mut_unchecked( - self, - ) -> Result, QueryAccessError> { - // SAFETY: - // - We have mutable access to all components of this entity. - // - Caller asserts the `QueryData` does not provide aliasing mutable references to the same component - unsafe { self.cell.get_components::() } - } - - /// Consumes self and returns components for the current entity that match the query `Q` for the world lifetime `'w`, - /// or `None` if the entity does not have the components required by the query `Q`. - /// - /// The checks for aliasing mutable references may be expensive. - /// If performance is a concern, consider making multiple calls to [`Self::get_mut`]. - /// If that is not possible, consider using [`Self::into_components_mut_unchecked`] to skip the checks. - /// - /// # Panics - /// - /// If the `QueryData` provides aliasing mutable references to the same component. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// #[derive(Component)] - /// struct X(usize); - /// #[derive(Component)] - /// struct Y(usize); - /// - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); - /// // Get mutable access to two components at once - /// let (mut x, mut y) = entity.into_components_mut::<(&mut X, &mut Y)>().unwrap(); - /// *x = X(1); - /// *y = Y(1); - /// ``` - /// - /// ```should_panic - /// # use bevy_ecs::prelude::*; - /// # - /// # #[derive(Component)] - /// # struct X(usize); - /// # - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0))).into_mutable(); - /// // This panics, as the `&mut X`s would alias: - /// entity.into_components_mut::<(&mut X, &mut X)>(); - /// ``` - pub fn into_components_mut( - self, - ) -> Result, QueryAccessError> { - has_conflicts::(self.cell.world().components())?; - - // SAFETY: we checked that there were not conflicting components above - unsafe { self.into_components_mut_unchecked::() } - } - /// Consumes `self` and gets access to the component of type `T` with the /// world `'w` lifetime for the current entity. /// @@ -368,8 +203,7 @@ impl<'w> EntityMut<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get_mut>(&mut self) -> Option> { - // SAFETY: &mut self implies exclusive access for duration of returned value - unsafe { self.cell.get_mut() } + self.reborrow().into_mut() } /// Gets mutable access to the component of type `T` for the current entity. @@ -380,10 +214,7 @@ impl<'w> EntityMut<'w> { /// - `T` must be a mutable component #[inline] pub unsafe fn get_mut_assume_mutable(&mut self) -> Option> { - // SAFETY: - // - &mut self implies exclusive access for duration of returned value - // - Caller ensures `T` is a mutable component - unsafe { self.cell.get_mut_assume_mutable() } + self.reborrow().into_mut_assume_mutable() } /// Consumes self and gets mutable access to the component of type `T` @@ -391,8 +222,11 @@ impl<'w> EntityMut<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn into_mut>(self) -> Option> { - // SAFETY: consuming `self` implies exclusive access - unsafe { self.cell.get_mut() } + // SAFETY: + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Consuming `self` implies exclusive access to components in `access`. + unsafe { self.cell.get_mut(self.access) } } /// Gets mutable access to the component of type `T` for the current entity. @@ -404,9 +238,11 @@ impl<'w> EntityMut<'w> { #[inline] pub unsafe fn into_mut_assume_mutable(self) -> Option> { // SAFETY: - // - Consuming `self` implies exclusive access - // - Caller ensures `T` is a mutable component - unsafe { self.cell.get_mut_assume_mutable() } + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Consuming `self` implies exclusive access to components in `access`. + // - Caller ensures `T` is a mutable component. + unsafe { self.cell.get_mut_assume_mutable(self.access) } } /// Retrieves the change ticks for the given component. This can be useful for implementing change @@ -602,10 +438,7 @@ impl<'w> EntityMut<'w> { &mut self, component_ids: F, ) -> Result, EntityComponentError> { - // SAFETY: - // - `&mut self` ensures that no references exist to this entity's components. - // - We have exclusive access to all components of this entity. - unsafe { component_ids.fetch_mut(self.cell) } + self.reborrow().into_mut_by_id(component_ids) } /// Returns untyped mutable reference(s) to component(s) for @@ -635,10 +468,7 @@ impl<'w> EntityMut<'w> { &mut self, component_ids: F, ) -> Result, EntityComponentError> { - // SAFETY: - // - `&mut self` ensures that no references exist to this entity's components. - // - We have exclusive access to all components of this entity. - unsafe { component_ids.fetch_mut_assume_mutable(self.cell) } + self.reborrow().into_mut_assume_mutable_by_id(component_ids) } /// Returns untyped mutable reference to component for @@ -664,9 +494,11 @@ impl<'w> EntityMut<'w> { component_ids: F, ) -> Result, EntityComponentError> { // SAFETY: - // - The caller must ensure simultaneous access is limited - // - to components that are mutually independent. - unsafe { component_ids.fetch_mut(self.cell) } + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Caller ensures exclusive access to components in `access` for + // duration of returned value. + unsafe { component_ids.fetch_mut(self.cell, self.access) } } /// Returns untyped mutable reference to component for @@ -694,9 +526,12 @@ impl<'w> EntityMut<'w> { component_ids: F, ) -> Result, EntityComponentError> { // SAFETY: - // - The caller must ensure simultaneous access is limited - // - to components that are mutually independent. - unsafe { component_ids.fetch_mut_assume_mutable(self.cell) } + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Caller ensures exclusive access to components in `access` for + // duration of returned value. + // - Caller ensures provided `ComponentId`s refer to mutable components. + unsafe { component_ids.fetch_mut_assume_mutable(self.cell, self.access) } } /// Consumes `self` and returns untyped mutable reference(s) @@ -727,9 +562,10 @@ impl<'w> EntityMut<'w> { component_ids: F, ) -> Result, EntityComponentError> { // SAFETY: - // - consuming `self` ensures that no references exist to this entity's components. - // - We have exclusive access to all components of this entity. - unsafe { component_ids.fetch_mut(self.cell) } + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Consuming `self` implies exclusive access to components in `access`. + unsafe { component_ids.fetch_mut(self.cell, self.access) } } /// Consumes `self` and returns untyped mutable reference(s) @@ -761,9 +597,11 @@ impl<'w> EntityMut<'w> { component_ids: F, ) -> Result, EntityComponentError> { // SAFETY: - // - consuming `self` ensures that no references exist to this entity's components. - // - We have exclusive access to all components of this entity. - unsafe { component_ids.fetch_mut_assume_mutable(self.cell) } + // - `self` was constructed with an `access` that doesn't violate aliasing + // rules for `cell`. + // - Consuming `self` implies exclusive access to components in `access`. + // - Caller ensures provided `ComponentId`s refer to mutable components. + unsafe { component_ids.fetch_mut_assume_mutable(self.cell, self.access) } } /// Returns the source code location from which this entity has been spawned. @@ -777,64 +615,36 @@ impl<'w> EntityMut<'w> { } } -impl<'w> From> for EntityRef<'w> { +impl<'w, A: AsAccess> From> for EntityRef<'w, A> { #[inline] - fn from(entity: EntityMut<'w>) -> Self { + fn from(entity: EntityMut<'w, A>) -> Self { entity.into_readonly() } } -impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> { +impl<'w, A: AsAccess> From<&'w EntityMut<'_, A>> for EntityRef<'w, A> { #[inline] - fn from(entity: &'a EntityMut<'_>) -> Self { + fn from(entity: &'w EntityMut<'_, A>) -> Self { entity.as_readonly() } } -impl<'w> From<&'w mut EntityMut<'_>> for EntityMut<'w> { +impl<'w, A: AsAccess> From<&'w mut EntityMut<'_, A>> for EntityMut<'w, A> { #[inline] - fn from(entity: &'w mut EntityMut<'_>) -> Self { + fn from(entity: &'w mut EntityMut<'_, A>) -> Self { entity.reborrow() } } -impl<'a> From> for FilteredEntityRef<'a, 'static> { - #[inline] - fn from(entity: EntityMut<'a>) -> Self { - entity.into_readonly().into_filtered() - } -} - -impl<'a> From<&'a EntityMut<'_>> for FilteredEntityRef<'a, 'static> { - #[inline] - fn from(entity: &'a EntityMut<'_>) -> Self { - entity.as_readonly().into_filtered() - } -} - -impl<'a> From> for FilteredEntityMut<'a, 'static> { - #[inline] - fn from(entity: EntityMut<'a>) -> Self { - entity.into_filtered() - } -} - -impl<'a> From<&'a mut EntityMut<'_>> for FilteredEntityMut<'a, 'static> { - #[inline] - fn from(entity: &'a mut EntityMut<'_>) -> Self { - entity.reborrow().into_filtered() - } -} - -impl PartialEq for EntityMut<'_> { +impl PartialEq for EntityMut<'_, A> { fn eq(&self, other: &Self) -> bool { self.entity() == other.entity() } } -impl Eq for EntityMut<'_> {} +impl Eq for EntityMut<'_, A> {} -impl PartialOrd for EntityMut<'_> { +impl PartialOrd for EntityMut<'_, A> { /// [`EntityMut`]'s comparison trait implementations match the underlying [`Entity`], /// and cannot discern between different worlds. fn partial_cmp(&self, other: &Self) -> Option { @@ -842,23 +652,23 @@ impl PartialOrd for EntityMut<'_> { } } -impl Ord for EntityMut<'_> { +impl Ord for EntityMut<'_, A> { fn cmp(&self, other: &Self) -> Ordering { self.entity().cmp(&other.entity()) } } -impl Hash for EntityMut<'_> { +impl Hash for EntityMut<'_, A> { fn hash(&self, state: &mut H) { self.entity().hash(state); } } -impl ContainsEntity for EntityMut<'_> { +impl ContainsEntity for EntityMut<'_, A> { fn entity(&self) -> Entity { self.id() } } // SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for EntityMut<'_> {} +unsafe impl EntityEquivalent for EntityMut<'_, A> {} diff --git a/crates/bevy_ecs/src/world/entity_access/entity_ref.rs b/crates/bevy_ecs/src/world/entity_access/entity_ref.rs index fd38ddc48e5e3..f80a2cba3afc3 100644 --- a/crates/bevy_ecs/src/world/entity_access/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_access/entity_ref.rs @@ -3,10 +3,9 @@ use crate::{ change_detection::{ComponentTicks, MaybeLocation, Tick}, component::{Component, ComponentId}, entity::{ContainsEntity, Entity, EntityEquivalent, EntityLocation}, - query::{Access, QueryAccessError, ReadOnlyQueryData, ReleaseStateQueryData}, world::{ - error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, DynamicComponentFetch, - FilteredEntityRef, Ref, + error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, All, AsAccess, + DynamicComponentFetch, Ref, }, }; @@ -16,7 +15,18 @@ use core::{ hash::{Hash, Hasher}, }; -/// A read-only reference to a particular [`Entity`] and all of its components. +/// Provides read-only access to a single [`Entity`] and the components allowed +/// by the [`AsAccess`] `A`. Plain `EntityRef`s have an [`AsAccess`] of +/// [`All`], providing access to all components of the entity. +/// +/// # [`AsAccess`]s +/// +/// Access kinds describe what you can access on an `EntityRef`. The default +/// kind is [`All`], which provides access to all components of the entity. +/// Other kinds, such as [`Filtered`] and [`Except`], can restrict access to +/// only a subset of components. +/// +/// See the documentation of [`AsAccess`] for more details. /// /// # Examples /// @@ -34,28 +44,30 @@ use core::{ /// } /// # bevy_ecs::system::assert_is_system(disjoint_system); /// ``` +/// +/// [`Filtered`]: crate::world::Filtered +/// [`Except`]: crate::world::Except #[derive(Copy, Clone)] -pub struct EntityRef<'w> { - cell: UnsafeEntityCell<'w>, +pub struct EntityRef<'w, A: AsAccess = All> { + pub(super) cell: UnsafeEntityCell<'w>, + access: A, } -impl<'w> EntityRef<'w> { +impl<'w, A: AsAccess> EntityRef<'w, A> { /// # Safety - /// - `cell` must have permission to read every component of the entity. - /// - No mutable accesses to any of the entity's components may exist - /// at the same time as the returned [`EntityRef`]. + /// + /// Caller must ensure `access` does not exceed the read permissions of `cell` + /// in a way that would violate Rust's aliasing rules, including simultaneous + /// access of `cell` via an `EntityMut` or any other means. #[inline] - pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self { - Self { cell } + pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>, access: A) -> Self { + Self { cell, access } } - /// Consumes `self` and returns a [`FilteredEntityRef`] which has read-only - /// access to all of the entity's components, with the world `'w` lifetime. + /// Returns a copy of the current [`AsAccess`]. #[inline] - pub fn into_filtered(self) -> FilteredEntityRef<'w, 'static> { - // SAFETY: - // - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`. - unsafe { FilteredEntityRef::new(self.cell, const { &Access::new_read_all() }) } + pub fn access(&self) -> A { + self.access } /// Returns the [ID](Entity) of the current entity. @@ -118,8 +130,9 @@ impl<'w> EntityRef<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get(&self) -> Option<&'w T> { - // SAFETY: We have read-only access to all components of this entity. - unsafe { self.cell.get::() } + // SAFETY: `self` was constructed with an `access` that doesn't violate + // Rust's aliasing rules for `cell`. + unsafe { self.cell.get::(self.access) } } /// Gets access to the component of type `T` for the current entity, @@ -128,16 +141,18 @@ impl<'w> EntityRef<'w> { /// Returns `None` if the entity does not have a component of type `T`. #[inline] pub fn get_ref(&self) -> Option> { - // SAFETY: We have read-only access to all components of this entity. - unsafe { self.cell.get_ref::() } + // SAFETY: `self` was constructed with an `access` that doesn't violate + // Rust's aliasing rules for `cell`. + unsafe { self.cell.get_ref::(self.access) } } /// Retrieves the change ticks for the given component. This can be useful for implementing change /// detection in custom runtimes. #[inline] pub fn get_change_ticks(&self) -> Option { - // SAFETY: We have read-only access to all components of this entity. - unsafe { self.cell.get_change_ticks::() } + // SAFETY: `self` was constructed with an `access` that doesn't violate + // Rust's aliasing rules for `cell`. + unsafe { self.cell.get_change_ticks::(self.access) } } /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change @@ -148,8 +163,9 @@ impl<'w> EntityRef<'w> { /// compile time.** #[inline] pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - // SAFETY: We have read-only access to all components of this entity. - unsafe { self.cell.get_change_ticks_by_id(component_id) } + // SAFETY: `self` was constructed with an `access` that doesn't violate + // Rust's aliasing rules for `cell`. + unsafe { self.cell.get_change_ticks_by_id(self.access, component_id) } } /// Returns untyped read-only reference(s) to component(s) for the @@ -261,29 +277,9 @@ impl<'w> EntityRef<'w> { &self, component_ids: F, ) -> Result, EntityComponentError> { - // SAFETY: We have read-only access to all components of this entity. - unsafe { component_ids.fetch_ref(self.cell) } - } - - /// Returns read-only components for the current entity that match the query `Q`. - /// - /// # Panics - /// - /// If the entity does not have the components required by the query `Q`. - pub fn components(&self) -> Q::Item<'w, 'static> { - self.get_components::() - .expect("Query does not match the current entity") - } - - /// Returns read-only components for the current entity that match the query `Q`, - /// or `None` if the entity does not have the components required by the query `Q`. - pub fn get_components( - &self, - ) -> Result, QueryAccessError> { - // SAFETY: - // - We have read-only access to all components of this entity. - // - The query is read-only, and read-only references cannot have conflicts. - unsafe { self.cell.get_components::() } + // SAFETY: `self` was constructed with an `access` that doesn't violate + // Rust's aliasing rules for `cell`. + unsafe { component_ids.fetch_ref(self.cell, self.access) } } /// Returns the source code location from which this entity has been spawned. @@ -297,29 +293,15 @@ impl<'w> EntityRef<'w> { } } -impl<'a> From> for FilteredEntityRef<'a, 'static> { - #[inline] - fn from(entity: EntityRef<'a>) -> Self { - entity.into_filtered() - } -} - -impl<'a> From<&EntityRef<'a>> for FilteredEntityRef<'a, 'static> { - #[inline] - fn from(entity: &EntityRef<'a>) -> Self { - entity.into_filtered() - } -} - -impl PartialEq for EntityRef<'_> { +impl PartialEq for EntityRef<'_, A> { fn eq(&self, other: &Self) -> bool { self.entity() == other.entity() } } -impl Eq for EntityRef<'_> {} +impl Eq for EntityRef<'_, A> {} -impl PartialOrd for EntityRef<'_> { +impl PartialOrd for EntityRef<'_, A> { /// [`EntityRef`]'s comparison trait implementations match the underlying [`Entity`], /// and cannot discern between different worlds. fn partial_cmp(&self, other: &Self) -> Option { @@ -327,23 +309,23 @@ impl PartialOrd for EntityRef<'_> { } } -impl Ord for EntityRef<'_> { +impl Ord for EntityRef<'_, A> { fn cmp(&self, other: &Self) -> Ordering { self.entity().cmp(&other.entity()) } } -impl Hash for EntityRef<'_> { +impl Hash for EntityRef<'_, A> { fn hash(&self, state: &mut H) { self.entity().hash(state); } } -impl ContainsEntity for EntityRef<'_> { +impl ContainsEntity for EntityRef<'_, A> { fn entity(&self) -> Entity { self.id() } } // SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for EntityRef<'_> {} +unsafe impl EntityEquivalent for EntityRef<'_, A> {} diff --git a/crates/bevy_ecs/src/world/entity_access/except.rs b/crates/bevy_ecs/src/world/entity_access/except.rs index 224d4011489d6..be819b36e4bb4 100644 --- a/crates/bevy_ecs/src/world/entity_access/except.rs +++ b/crates/bevy_ecs/src/world/entity_access/except.rs @@ -1,472 +1,78 @@ use crate::{ bundle::Bundle, - change_detection::{ComponentTicks, MaybeLocation, MutUntyped, Tick}, - component::{Component, ComponentId, Components, Mutable}, - entity::{ContainsEntity, Entity, EntityEquivalent}, - query::Access, - world::{ - unsafe_world_cell::UnsafeEntityCell, DynamicComponentFetch, FilteredEntityMut, - FilteredEntityRef, Mut, Ref, - }, + world::{EntityMut, EntityRef, Except, Filtered, FilteredEntityMut, FilteredEntityRef}, }; -use bevy_ptr::Ptr; -use core::{ - any::TypeId, - cmp::Ordering, - hash::{Hash, Hasher}, - marker::PhantomData, -}; - -/// Provides read-only access to a single entity and all its components, save -/// for an explicitly-enumerated set. -pub struct EntityRefExcept<'w, 's, B> -where - B: Bundle, -{ - entity: UnsafeEntityCell<'w>, - access: &'s Access, - phantom: PhantomData, -} - -impl<'w, 's, B> EntityRefExcept<'w, 's, B> -where - B: Bundle, -{ - /// # Safety - /// Other users of `UnsafeEntityCell` must only have mutable access to the components in `B`. - pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self { - Self { - entity, - access, - phantom: PhantomData, - } - } +/// Provides read-only access to a single [`Entity`] and all its components, +/// except those mentioned in the [`Bundle`] `B` at compile time. This is an +/// [`EntityRef`] with an [`AsAccess`] of [`Except`]. +/// +/// [`Entity`]: crate::world::Entity +/// [`AsAccess`]: crate::world::AsAccess +pub type EntityRefExcept<'w, 's, B> = EntityRef<'w, Except<'s, B>>; - /// Consumes `self` and returns a [`FilteredEntityRef`], which provides - /// read-only access to all of the entity's components, except for the ones - /// in `B`. - #[inline] +impl<'w, 's, B: Bundle> EntityRefExcept<'w, 's, B> { + /// Consumes `self` and returns a [`FilteredEntityRef`] with the same access + /// permissions. pub fn into_filtered(self) -> FilteredEntityRef<'w, 's> { // SAFETY: - // - The FilteredEntityRef has the same component access as the given EntityRefExcept. - unsafe { FilteredEntityRef::new(self.entity, self.access) } - } - - /// Returns the [ID](Entity) of the current entity. - #[inline] - #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] - pub fn id(&self) -> Entity { - self.entity.id() - } - - /// Gets access to the component of type `C` for the current entity. Returns - /// `None` if the component doesn't have a component of that type or if the - /// type is one of the excluded components. - #[inline] - pub fn get(&self) -> Option<&'w C> - where - C: Component, - { - let components = self.entity.world().components(); - let id = components.valid_component_id::()?; - if bundle_contains_component::(components, id) { - None - } else { - // SAFETY: We have read access for all components that weren't - // covered by the `contains` check above. - unsafe { self.entity.get() } - } - } - - /// Gets access to the component of type `C` for the current entity, - /// including change detection information. Returns `None` if the component - /// doesn't have a component of that type or if the type is one of the - /// excluded components. - #[inline] - pub fn get_ref(&self) -> Option> - where - C: Component, - { - let components = self.entity.world().components(); - let id = components.valid_component_id::()?; - if bundle_contains_component::(components, id) { - None - } else { - // SAFETY: We have read access for all components that weren't - // covered by the `contains` check above. - unsafe { self.entity.get_ref() } - } - } - - /// Returns the source code location from which this entity has been spawned. - pub fn spawned_by(&self) -> MaybeLocation { - self.entity.spawned_by() - } - - /// Returns the [`Tick`] at which this entity has been spawned. - pub fn spawn_tick(&self) -> Tick { - self.entity.spawn_tick() - } - - /// Gets the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`EntityRefExcept::get`], this returns a raw pointer to the component, - /// which is only valid while the [`EntityRefExcept`] is alive. - #[inline] - pub fn get_by_id(&self, component_id: ComponentId) -> Option> { - let components = self.entity.world().components(); - (!bundle_contains_component::(components, component_id)) - .then(|| { - // SAFETY: We have read access for this component - unsafe { self.entity.get_by_id(component_id) } - }) - .flatten() - } - - /// Returns `true` if the current entity has a component of type `T`. - /// Otherwise, this returns `false`. - /// - /// ## Notes - /// - /// If you do not know the concrete type of a component, consider using - /// [`Self::contains_id`] or [`Self::contains_type_id`]. - #[inline] - pub fn contains(&self) -> bool { - self.contains_type_id(TypeId::of::()) - } - - /// Returns `true` if the current entity has a component identified by `component_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using - /// [`Self::contains_type_id`]. - #[inline] - pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.entity.contains_id(component_id) - } - - /// Returns `true` if the current entity has a component with the type identified by `type_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. - #[inline] - pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.entity.contains_type_id(type_id) - } - - /// Retrieves the change ticks for the given component. This can be useful for implementing change - /// detection in custom runtimes. - #[inline] - pub fn get_change_ticks(&self) -> Option { - let component_id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - let components = self.entity.world().components(); - (!bundle_contains_component::(components, component_id)) - .then(|| { - // SAFETY: We have read access - unsafe { self.entity.get_change_ticks::() } - }) - .flatten() - } - - /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change - /// detection in custom runtimes. - /// - /// **You should prefer to use the typed API [`Self::get_change_ticks`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - #[inline] - pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - let components = self.entity.world().components(); - (!bundle_contains_component::(components, component_id)) - .then(|| { - // SAFETY: We have read access - unsafe { self.entity.get_change_ticks_by_id(component_id) } - }) - .flatten() + // - Read permissions of the `Except` access are preserved in the `Filtered` access. + unsafe { EntityRef::new(self.cell, Filtered(self.access().0)) } } } impl<'w, 's, B: Bundle> From> for FilteredEntityRef<'w, 's> { + #[inline] fn from(entity: EntityRefExcept<'w, 's, B>) -> Self { entity.into_filtered() } } impl<'w, 's, B: Bundle> From<&EntityRefExcept<'w, 's, B>> for FilteredEntityRef<'w, 's> { + #[inline] fn from(entity: &EntityRefExcept<'w, 's, B>) -> Self { entity.into_filtered() } } -impl Clone for EntityRefExcept<'_, '_, B> { - fn clone(&self) -> Self { - *self - } -} - -impl Copy for EntityRefExcept<'_, '_, B> {} - -impl PartialEq for EntityRefExcept<'_, '_, B> { - fn eq(&self, other: &Self) -> bool { - self.entity() == other.entity() - } -} - -impl Eq for EntityRefExcept<'_, '_, B> {} - -impl PartialOrd for EntityRefExcept<'_, '_, B> { - /// [`EntityRefExcept`]'s comparison trait implementations match the underlying [`Entity`], - /// and cannot discern between different worlds. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for EntityRefExcept<'_, '_, B> { - fn cmp(&self, other: &Self) -> Ordering { - self.entity().cmp(&other.entity()) - } -} - -impl Hash for EntityRefExcept<'_, '_, B> { - fn hash(&self, state: &mut H) { - self.entity().hash(state); - } -} - -impl ContainsEntity for EntityRefExcept<'_, '_, B> { - fn entity(&self) -> Entity { - self.id() - } -} - -// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for EntityRefExcept<'_, '_, B> {} - -/// Provides mutable access to all components of an entity, with the exception -/// of an explicit set. +/// Provides mutable access to a single [`Entity`] and all its components, +/// except those mentioned in the [`Bundle`] `B` at compile time. This is an +/// [`EntityMut`] with an [`AsAccess`] of [`Except`]. /// /// This is a rather niche type that should only be used if you need access to /// *all* components of an entity, while still allowing you to consult other /// queries that might match entities that this query also matches. If you don't /// need access to all components, prefer a standard query with a /// [`Without`](`crate::query::Without`) filter. -pub struct EntityMutExcept<'w, 's, B> -where - B: Bundle, -{ - entity: UnsafeEntityCell<'w>, - access: &'s Access, - phantom: PhantomData, -} - -impl<'w, 's, B> EntityMutExcept<'w, 's, B> -where - B: Bundle, -{ - /// # Safety - /// Other users of `UnsafeEntityCell` must not have access to any components not in `B`. - pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self { - Self { - entity, - access, - phantom: PhantomData, - } - } - - /// Returns the [ID](Entity) of the current entity. - #[inline] - #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] - pub fn id(&self) -> Entity { - self.entity.id() - } - - /// Returns a new instance with a shorter lifetime. - /// - /// This is useful if you have `&mut EntityMutExcept`, but you need - /// `EntityMutExcept`. - #[inline] - pub fn reborrow(&mut self) -> EntityMutExcept<'_, 's, B> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - `&mut self` ensures there are no other accesses to the applicable components. - unsafe { Self::new(self.entity, self.access) } - } - - /// Consumes `self` and returns read-only access to all of the entity's - /// components, except for the ones in `B`. - #[inline] - pub fn into_readonly(self) -> EntityRefExcept<'w, 's, B> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - Consuming `self` ensures there are no other accesses to the applicable components. - unsafe { EntityRefExcept::new(self.entity, self.access) } - } - - /// Gets read-only access to all of the entity's components, except for the - /// ones in `B`. - #[inline] - pub fn as_readonly(&self) -> EntityRefExcept<'_, 's, B> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - `&self` ensures there are no mutable accesses to the applicable components. - unsafe { EntityRefExcept::new(self.entity, self.access) } - } +/// +/// [`Entity`]: crate::world::Entity +/// [`AsAccess`]: crate::world::AsAccess +pub type EntityMutExcept<'w, 's, B> = EntityMut<'w, Except<'s, B>>; - /// Consumes `self` and returns a [`FilteredEntityMut`], which provides - /// mutable access to all of the entity's components, except for the ones in - /// `B`. +impl<'w, 's, B: Bundle> EntityMutExcept<'w, 's, B> { + /// Consumes `self` and returns a [`FilteredEntityMut`] with the same access + /// permissions. #[inline] pub fn into_filtered(self) -> FilteredEntityMut<'w, 's> { // SAFETY: - // - The FilteredEntityMut has the same component access as the given EntityMutExcept. - // - Consuming `self` ensures there are no other accesses to the applicable components. - unsafe { FilteredEntityMut::new(self.entity, self.access) } - } - - /// Get access to the underlying [`UnsafeEntityCell`] - #[inline] - pub fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> { - self.entity - } - - /// Gets access to the component of type `C` for the current entity. Returns - /// `None` if the component doesn't have a component of that type or if the - /// type is one of the excluded components. - #[inline] - pub fn get(&self) -> Option<&'_ C> - where - C: Component, - { - self.as_readonly().get() - } - - /// Gets access to the component of type `C` for the current entity, - /// including change detection information. Returns `None` if the component - /// doesn't have a component of that type or if the type is one of the - /// excluded components. - #[inline] - pub fn get_ref(&self) -> Option> - where - C: Component, - { - self.as_readonly().get_ref() - } - - /// Gets mutable access to the component of type `C` for the current entity. - /// Returns `None` if the component doesn't have a component of that type or - /// if the type is one of the excluded components. - #[inline] - pub fn get_mut(&mut self) -> Option> - where - C: Component, - { - let components = self.entity.world().components(); - let id = components.valid_component_id::()?; - if bundle_contains_component::(components, id) { - None - } else { - // SAFETY: We have write access for all components that weren't - // covered by the `contains` check above. - unsafe { self.entity.get_mut() } - } - } - - /// Returns the source code location from which this entity has been spawned. - pub fn spawned_by(&self) -> MaybeLocation { - self.entity.spawned_by() - } - - /// Returns the [`Tick`] at which this entity has been spawned. - pub fn spawn_tick(&self) -> Tick { - self.entity.spawn_tick() - } - - /// Returns `true` if the current entity has a component of type `T`. - /// Otherwise, this returns `false`. - /// - /// ## Notes - /// - /// If you do not know the concrete type of a component, consider using - /// [`Self::contains_id`] or [`Self::contains_type_id`]. - #[inline] - pub fn contains(&self) -> bool { - self.contains_type_id(TypeId::of::()) - } - - /// Returns `true` if the current entity has a component identified by `component_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using - /// [`Self::contains_type_id`]. - #[inline] - pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.entity.contains_id(component_id) - } - - /// Returns `true` if the current entity has a component with the type identified by `type_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. - #[inline] - pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.entity.contains_type_id(type_id) + // - Read and write permissions of the `Except` access are preserved in + // the `Filtered` access. + // - Consuming `self` ensures there are no other accesses. + unsafe { EntityMut::new(self.cell, Filtered(self.access().0)) } } +} - /// Gets the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`EntityMutExcept::get`], this returns a raw pointer to the component, - /// which is only valid while the [`EntityMutExcept`] is alive. +impl<'w, 's, B: Bundle> From> for FilteredEntityRef<'w, 's> { #[inline] - pub fn get_by_id(&'w self, component_id: ComponentId) -> Option> { - self.as_readonly().get_by_id(component_id) + fn from(entity: EntityMutExcept<'w, 's, B>) -> Self { + entity.into_readonly().into_filtered() } +} - /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get_mut`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`EntityMutExcept::get_mut`], this returns a raw pointer to the component, - /// which is only valid while the [`EntityMutExcept`] is alive. +impl<'w, 's, B: Bundle> From<&'w EntityMutExcept<'_, 's, B>> for FilteredEntityRef<'w, 's> { #[inline] - pub fn get_mut_by_id( - &mut self, - component_id: ComponentId, - ) -> Option> { - let components = self.entity.world().components(); - (!bundle_contains_component::(components, component_id)) - .then(|| { - // SAFETY: We have write access - unsafe { self.entity.get_mut_by_id(component_id).ok() } - }) - .flatten() + fn from(entity: &'w EntityMutExcept<'_, 's, B>) -> Self { + entity.as_readonly().into_filtered() } } @@ -483,72 +89,3 @@ impl<'w, 's, B: Bundle> From<&'w mut EntityMutExcept<'_, 's, B>> for FilteredEnt entity.reborrow().into_filtered() } } - -impl<'w, 's, B: Bundle> From<&'w mut EntityMutExcept<'_, 's, B>> for EntityMutExcept<'w, 's, B> { - #[inline] - fn from(entity: &'w mut EntityMutExcept<'_, 's, B>) -> Self { - entity.reborrow() - } -} - -impl<'w, 's, B: Bundle> From> for EntityRefExcept<'w, 's, B> { - #[inline] - fn from(entity: EntityMutExcept<'w, 's, B>) -> Self { - entity.into_readonly() - } -} - -impl<'w, 's, B: Bundle> From<&'w EntityMutExcept<'_, 's, B>> for EntityRefExcept<'w, 's, B> { - #[inline] - fn from(entity: &'w EntityMutExcept<'_, 's, B>) -> Self { - entity.as_readonly() - } -} - -impl PartialEq for EntityMutExcept<'_, '_, B> { - fn eq(&self, other: &Self) -> bool { - self.entity() == other.entity() - } -} - -impl Eq for EntityMutExcept<'_, '_, B> {} - -impl PartialOrd for EntityMutExcept<'_, '_, B> { - /// [`EntityMutExcept`]'s comparison trait implementations match the underlying [`Entity`], - /// and cannot discern between different worlds. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for EntityMutExcept<'_, '_, B> { - fn cmp(&self, other: &Self) -> Ordering { - self.entity().cmp(&other.entity()) - } -} - -impl Hash for EntityMutExcept<'_, '_, B> { - fn hash(&self, state: &mut H) { - self.entity().hash(state); - } -} - -impl ContainsEntity for EntityMutExcept<'_, '_, B> { - fn entity(&self) -> Entity { - self.id() - } -} - -// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for EntityMutExcept<'_, '_, B> {} - -fn bundle_contains_component(components: &Components, query_id: ComponentId) -> bool -where - B: Bundle, -{ - let mut found = false; - for id in B::get_component_ids(components).flatten() { - found = found || id == query_id; - } - found -} diff --git a/crates/bevy_ecs/src/world/entity_access/filtered.rs b/crates/bevy_ecs/src/world/entity_access/filtered.rs index de366205f94ed..57b550926d907 100644 --- a/crates/bevy_ecs/src/world/entity_access/filtered.rs +++ b/crates/bevy_ecs/src/world/entity_access/filtered.rs @@ -1,25 +1,18 @@ use crate::{ - archetype::Archetype, - change_detection::{ComponentTicks, MaybeLocation, MutUntyped, Tick}, - component::{Component, ComponentId, Mutable}, - entity::{ContainsEntity, Entity, EntityEquivalent, EntityLocation}, query::Access, - world::{unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityRef, Mut, Ref}, + world::{ + entity_access::Filtered, unsafe_world_cell::UnsafeEntityCell, All, EntityMut, EntityRef, + }, }; -use bevy_ptr::Ptr; -use core::{ - any::TypeId, - cmp::Ordering, - hash::{Hash, Hasher}, -}; use thiserror::Error; -/// Provides read-only access to a single entity and some of its components defined by the contained [`Access`]. +/// Provides read-only access to a single [`Entity`] and some of its components, +/// as defined by the contained [`Access`] at runtime. This is an [`EntityRef`] +/// with an [`AsAccess`] of [`Filtered`]. /// -/// To define the access when used as a [`QueryData`](crate::query::QueryData), -/// use a [`QueryBuilder`](crate::query::QueryBuilder) or [`QueryParamBuilder`](crate::system::QueryParamBuilder). -/// The [`FilteredEntityRef`] must be the entire [`QueryData`](crate::query::QueryData), and not nested inside a tuple with other data. +/// To define the access when used as a [`QueryData`], use a [`QueryBuilder`] or +/// [`QueryParamBuilder`]. /// /// ``` /// # use bevy_ecs::{prelude::*, world::FilteredEntityRef}; @@ -38,248 +31,51 @@ use thiserror::Error; /// let filtered_entity: FilteredEntityRef = query.single(&mut world).unwrap(); /// let component: &A = filtered_entity.get().unwrap(); /// ``` -#[derive(Clone, Copy)] -pub struct FilteredEntityRef<'w, 's> { - entity: UnsafeEntityCell<'w>, - access: &'s Access, -} +/// +/// [`Entity`]: crate::world::Entity +/// [`AsAccess`]: crate::world::AsAccess +/// [`QueryData`]: crate::query::QueryData +/// [`QueryBuilder`]: crate::query::QueryBuilder +/// [`QueryParamBuilder`]: crate::system::QueryParamBuilder +pub type FilteredEntityRef<'w, 's> = EntityRef<'w, Filtered<'s>>; impl<'w, 's> FilteredEntityRef<'w, 's> { - /// # Safety - /// - No `&mut World` can exist from the underlying `UnsafeWorldCell` - /// - If `access` takes read access to a component no mutable reference to that - /// component can exist at the same time as the returned [`FilteredEntityMut`] - /// - If `access` takes any access for a component `entity` must have that component. - #[inline] - pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self { - Self { entity, access } - } - - /// Consumes self and returns read-only access to the entity and *all* of - /// its components, with the world `'w` lifetime. Returns an error if the - /// access does not include read access to all components. + /// Consumes `self` and attempts to return an [`EntityRef`] with [`All`] + /// access. /// /// # Errors /// - /// - [`TryFromFilteredError::MissingReadAllAccess`] - if the access does not include read access to all components. - #[inline] + /// Returns [`TryFromFilteredError::MissingReadAllAccess`] if the contained + /// [`Access`] does not have read access to all components. pub fn try_into_all(self) -> Result, TryFromFilteredError> { - if !self.access.has_read_all() { + if !self.access().has_read_all() { Err(TryFromFilteredError::MissingReadAllAccess) } else { - // SAFETY: check above guarantees read-only access to all components of the entity. - Ok(unsafe { EntityRef::new(self.entity) }) + // SAFETY: `Access::has_read_all` check satisfies the `All` access + // kind for `EntityRef`. + Ok(unsafe { EntityRef::new(self.cell, All) }) } } - - /// Returns the [ID](Entity) of the current entity. - #[inline] - #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] - pub fn id(&self) -> Entity { - self.entity.id() - } - - /// Gets metadata indicating the location where the current entity is stored. - #[inline] - pub fn location(&self) -> EntityLocation { - self.entity.location() - } - - /// Returns the archetype that the current entity belongs to. - #[inline] - pub fn archetype(&self) -> &Archetype { - self.entity.archetype() - } - - /// Returns a reference to the underlying [`Access`]. - #[inline] - pub fn access(&self) -> &Access { - self.access - } - - /// Returns `true` if the current entity has a component of type `T`. - /// Otherwise, this returns `false`. - /// - /// ## Notes - /// - /// If you do not know the concrete type of a component, consider using - /// [`Self::contains_id`] or [`Self::contains_type_id`]. - #[inline] - pub fn contains(&self) -> bool { - self.contains_type_id(TypeId::of::()) - } - - /// Returns `true` if the current entity has a component identified by `component_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using - /// [`Self::contains_type_id`]. - #[inline] - pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.entity.contains_id(component_id) - } - - /// Returns `true` if the current entity has a component with the type identified by `type_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. - #[inline] - pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.entity.contains_type_id(type_id) - } - - /// Gets access to the component of type `T` for the current entity. - /// Returns `None` if the entity does not have a component of type `T`. - #[inline] - pub fn get(&self) -> Option<&'w T> { - let id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - self.access - .has_component_read(id) - // SAFETY: We have read access - .then(|| unsafe { self.entity.get() }) - .flatten() - } - - /// Gets access to the component of type `T` for the current entity, - /// including change detection information as a [`Ref`]. - /// - /// Returns `None` if the entity does not have a component of type `T`. - #[inline] - pub fn get_ref(&self) -> Option> { - let id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - self.access - .has_component_read(id) - // SAFETY: We have read access - .then(|| unsafe { self.entity.get_ref() }) - .flatten() - } - - /// Retrieves the change ticks for the given component. This can be useful for implementing change - /// detection in custom runtimes. - #[inline] - pub fn get_change_ticks(&self) -> Option { - let id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - self.access - .has_component_read(id) - // SAFETY: We have read access - .then(|| unsafe { self.entity.get_change_ticks::() }) - .flatten() - } - - /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change - /// detection in custom runtimes. - /// - /// **You should prefer to use the typed API [`Self::get_change_ticks`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - #[inline] - pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - self.access - .has_component_read(component_id) - // SAFETY: We have read access - .then(|| unsafe { self.entity.get_change_ticks_by_id(component_id) }) - .flatten() - } - - /// Gets the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`FilteredEntityRef::get`], this returns a raw pointer to the component, - /// which is only valid while the [`FilteredEntityRef`] is alive. - #[inline] - pub fn get_by_id(&self, component_id: ComponentId) -> Option> { - self.access - .has_component_read(component_id) - // SAFETY: We have read access - .then(|| unsafe { self.entity.get_by_id(component_id) }) - .flatten() - } - - /// Returns the source code location from which this entity has been spawned. - pub fn spawned_by(&self) -> MaybeLocation { - self.entity.spawned_by() - } - - /// Returns the [`Tick`] at which this entity has been spawned. - pub fn spawn_tick(&self) -> Tick { - self.entity.spawn_tick() - } } -impl<'a> TryFrom> for EntityRef<'a> { +impl<'w> TryFrom> for EntityRef<'w> { type Error = TryFromFilteredError; - fn try_from(entity: FilteredEntityRef<'a, '_>) -> Result { + #[inline] + fn try_from(entity: FilteredEntityRef<'w, '_>) -> Result { entity.try_into_all() } } -impl<'a> TryFrom<&FilteredEntityRef<'a, '_>> for EntityRef<'a> { +impl<'w> TryFrom<&FilteredEntityRef<'w, '_>> for EntityRef<'w> { type Error = TryFromFilteredError; - fn try_from(entity: &FilteredEntityRef<'a, '_>) -> Result { + #[inline] + fn try_from(entity: &FilteredEntityRef<'w, '_>) -> Result { entity.try_into_all() } } -impl PartialEq for FilteredEntityRef<'_, '_> { - fn eq(&self, other: &Self) -> bool { - self.entity() == other.entity() - } -} - -impl Eq for FilteredEntityRef<'_, '_> {} - -impl PartialOrd for FilteredEntityRef<'_, '_> { - /// [`FilteredEntityRef`]'s comparison trait implementations match the underlying [`Entity`], - /// and cannot discern between different worlds. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for FilteredEntityRef<'_, '_> { - fn cmp(&self, other: &Self) -> Ordering { - self.entity().cmp(&other.entity()) - } -} - -impl Hash for FilteredEntityRef<'_, '_> { - fn hash(&self, state: &mut H) { - self.entity().hash(state); - } -} - -impl ContainsEntity for FilteredEntityRef<'_, '_> { - fn entity(&self) -> Entity { - self.id() - } -} - -// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for FilteredEntityRef<'_, '_> {} - /// Variant of [`FilteredEntityMut`] that can be used to create copies of a [`FilteredEntityMut`], as long /// as the user ensures that these won't cause aliasing violations. /// @@ -321,8 +117,8 @@ impl<'w, 's> UnsafeFilteredEntityMut<'w, 's> { #[inline] pub fn new_readonly(filtered_entity_mut: &FilteredEntityMut<'w, 's>) -> Self { Self { - entity: filtered_entity_mut.entity, - access: filtered_entity_mut.access, + entity: filtered_entity_mut.cell, + access: filtered_entity_mut.access().0, } } @@ -332,16 +128,16 @@ impl<'w, 's> UnsafeFilteredEntityMut<'w, 's> { /// - The user must ensure that no aliasing violations occur when using the returned `FilteredEntityMut`. #[inline] pub unsafe fn into_mut(self) -> FilteredEntityMut<'w, 's> { - // SAFETY: Upheld by caller. - unsafe { FilteredEntityMut::new(self.entity, self.access) } + EntityMut::new(self.entity, Filtered(self.access)) } } -/// Provides mutable access to a single entity and some of its components defined by the contained [`Access`]. +/// Provides mutable access to a single [`Entity`] and some of its components, +/// as defined by the contained [`Access`] at runtime. This is an [`EntityMut`] +/// with an [`AsAccess`] of [`Filtered`]. /// -/// To define the access when used as a [`QueryData`](crate::query::QueryData), -/// use a [`QueryBuilder`](crate::query::QueryBuilder) or [`QueryParamBuilder`](crate::system::QueryParamBuilder). -/// The `FilteredEntityMut` must be the entire `QueryData`, and not nested inside a tuple with other data. +/// To define the access when used as a [`QueryData`], use a [`QueryBuilder`] or +/// [`QueryParamBuilder`]. /// /// ``` /// # use bevy_ecs::{prelude::*, world::FilteredEntityMut}; @@ -362,444 +158,74 @@ impl<'w, 's> UnsafeFilteredEntityMut<'w, 's> { /// ``` /// /// Also see [`UnsafeFilteredEntityMut`] for a way to bypass borrow-checker restrictions. -pub struct FilteredEntityMut<'w, 's> { - entity: UnsafeEntityCell<'w>, - access: &'s Access, -} +/// +/// [`Entity`]: crate::world::Entity +/// [`AsAccess`]: crate::world::AsAccess +/// [`QueryData`]: crate::query::QueryData +/// [`QueryBuilder`]: crate::query::QueryBuilder +/// [`QueryParamBuilder`]: crate::system::QueryParamBuilder +pub type FilteredEntityMut<'w, 's> = EntityMut<'w, Filtered<'s>>; impl<'w, 's> FilteredEntityMut<'w, 's> { - /// # Safety - /// - No `&mut World` can exist from the underlying `UnsafeWorldCell` - /// - If `access` takes read access to a component no mutable reference to that - /// component can exist at the same time as the returned [`FilteredEntityMut`] - /// - If `access` takes write access to a component, no reference to that component - /// may exist at the same time as the returned [`FilteredEntityMut`] - /// - If `access` takes any access for a component `entity` must have that component. - #[inline] - pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self { - Self { entity, access } - } - - /// Returns a new instance with a shorter lifetime. - /// This is useful if you have `&mut FilteredEntityMut`, but you need `FilteredEntityMut`. - #[inline] - pub fn reborrow(&mut self) -> FilteredEntityMut<'_, 's> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - `&mut self` ensures there are no other accesses to the applicable components. - unsafe { Self::new(self.entity, self.access) } - } - - /// Consumes `self` and returns read-only access to all of the entity's - /// components, with the world `'w` lifetime. - #[inline] - pub fn into_readonly(self) -> FilteredEntityRef<'w, 's> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - Consuming `self` ensures there are no other accesses to the applicable components. - unsafe { FilteredEntityRef::new(self.entity, self.access) } - } - - /// Gets read-only access to all of the entity's components. - #[inline] - pub fn as_readonly(&self) -> FilteredEntityRef<'_, 's> { - // SAFETY: - // - We have exclusive access to the entire entity and the applicable components. - // - `&self` ensures there are no mutable accesses to the applicable components. - unsafe { FilteredEntityRef::new(self.entity, self.access) } - } - - /// Consumes self and returns mutable access to the entity and *all* of - /// its components, with the world `'w` lifetime. Returns an error if the - /// access does not include read and write access to all components. + /// Consumes `self` and attempts to return an [`EntityMut`] with [`All`] access. /// /// # Errors /// - /// - [`TryFromFilteredError::MissingReadAllAccess`] - if the access does not include read access to all components. - /// - [`TryFromFilteredError::MissingWriteAllAccess`] - if the access does not include write access to all components. - #[inline] + /// - Returns [`TryFromFilteredError::MissingReadAllAccess`] if the contained + /// [`Access`] does not have read access to all components. + /// - Returns [`TryFromFilteredError::MissingWriteAllAccess`] if the contained + /// [`Access`] does not have write access to all components. pub fn try_into_all(self) -> Result, TryFromFilteredError> { - if !self.access.has_read_all() { + if !self.access().has_read_all() { Err(TryFromFilteredError::MissingReadAllAccess) - } else if !self.access.has_write_all() { + } else if !self.access().has_write_all() { Err(TryFromFilteredError::MissingWriteAllAccess) } else { - // SAFETY: check above guarantees exclusive access to all components of the entity. - Ok(unsafe { EntityMut::new(self.entity) }) + // SAFETY: `Access::has_read_all` and `Access::has_write_all` checks + // satisfy the `All` access for `EntityMut`. + Ok(unsafe { EntityMut::new(self.cell, All) }) } } - - /// Get access to the underlying [`UnsafeEntityCell`]. - #[inline] - pub fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> { - self.entity - } - - /// Returns the [ID](Entity) of the current entity. - #[inline] - #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."] - pub fn id(&self) -> Entity { - self.entity.id() - } - - /// Gets metadata indicating the location where the current entity is stored. - #[inline] - pub fn location(&self) -> EntityLocation { - self.entity.location() - } - - /// Returns the archetype that the current entity belongs to. - #[inline] - pub fn archetype(&self) -> &Archetype { - self.entity.archetype() - } - - /// Returns a reference to the underlying [`Access`]. - #[inline] - pub fn access(&self) -> &Access { - self.access - } - - /// Returns `true` if the current entity has a component of type `T`. - /// Otherwise, this returns `false`. - /// - /// ## Notes - /// - /// If you do not know the concrete type of a component, consider using - /// [`Self::contains_id`] or [`Self::contains_type_id`]. - #[inline] - pub fn contains(&self) -> bool { - self.contains_type_id(TypeId::of::()) - } - - /// Returns `true` if the current entity has a component identified by `component_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using - /// [`Self::contains_type_id`]. - #[inline] - pub fn contains_id(&self, component_id: ComponentId) -> bool { - self.entity.contains_id(component_id) - } - - /// Returns `true` if the current entity has a component with the type identified by `type_id`. - /// Otherwise, this returns false. - /// - /// ## Notes - /// - /// - If you know the concrete type of the component, you should prefer [`Self::contains`]. - /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`]. - #[inline] - pub fn contains_type_id(&self, type_id: TypeId) -> bool { - self.entity.contains_type_id(type_id) - } - - /// Gets access to the component of type `T` for the current entity. - /// Returns `None` if the entity does not have a component of type `T`. - #[inline] - pub fn get(&self) -> Option<&'_ T> { - self.as_readonly().get() - } - - /// Gets access to the component of type `T` for the current entity, - /// including change detection information as a [`Ref`]. - /// - /// Returns `None` if the entity does not have a component of type `T`. - #[inline] - pub fn get_ref(&self) -> Option> { - self.as_readonly().get_ref() - } - - /// Gets mutable access to the component of type `T` for the current entity. - /// Returns `None` if the entity does not have a component of type `T` or if - /// the access does not include write access to `T`. - #[inline] - pub fn get_mut>(&mut self) -> Option> { - // SAFETY: we use a mutable reference to self, so we cannot use the `FilteredEntityMut` to access - // another component - unsafe { self.get_mut_unchecked() } - } - - /// Gets mutable access to the component of type `T` for the current entity. - /// Returns `None` if the entity does not have a component of type `T` or if - /// the access does not include write access to `T`. - /// - /// This only requires `&self`, and so may be used to get mutable access to multiple components. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::{prelude::*, world::FilteredEntityMut}; - /// # - /// #[derive(Component)] - /// struct X(usize); - /// #[derive(Component)] - /// struct Y(usize); - /// - /// # let mut world = World::default(); - /// let mut entity = world.spawn((X(0), Y(0))).into_mutable(); - /// - /// // This gives the `FilteredEntityMut` access to `&mut X` and `&mut Y`. - /// let mut query = QueryBuilder::::new(&mut world) - /// .data::<(&mut X, &mut Y)>() - /// .build(); - /// - /// let mut filtered_entity: FilteredEntityMut = query.single_mut(&mut world).unwrap(); - /// - /// // Get mutable access to two components at once - /// // SAFETY: We don't take any other references to `X` from this entity - /// let mut x = unsafe { filtered_entity.get_mut_unchecked::() }.unwrap(); - /// // SAFETY: We don't take any other references to `Y` from this entity - /// let mut y = unsafe { filtered_entity.get_mut_unchecked::() }.unwrap(); - /// *x = X(1); - /// *y = Y(1); - /// ``` - /// - /// # Safety - /// - /// No other references to the same component may exist at the same time as the returned reference. - /// - /// # See also - /// - /// - [`get_mut`](Self::get_mut) for the safe version. - #[inline] - pub unsafe fn get_mut_unchecked>( - &self, - ) -> Option> { - let id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - self.access - .has_component_write(id) - // SAFETY: We have permission to access the component mutable - // and we promise to not create other references to the same component - .then(|| unsafe { self.entity.get_mut() }) - .flatten() - } - - /// Consumes self and gets mutable access to the component of type `T` - /// with the world `'w` lifetime for the current entity. - /// Returns `None` if the entity does not have a component of type `T`. - #[inline] - pub fn into_mut>(self) -> Option> { - // SAFETY: - // - We have write access - // - The bound `T: Component` ensures the component is mutable - unsafe { self.into_mut_assume_mutable() } - } - - /// Consumes self and gets mutable access to the component of type `T` - /// with the world `'w` lifetime for the current entity. - /// Returns `None` if the entity does not have a component of type `T`. - /// - /// # Safety - /// - /// - `T` must be a mutable component - #[inline] - pub unsafe fn into_mut_assume_mutable(self) -> Option> { - let id = self - .entity - .world() - .components() - .get_valid_id(TypeId::of::())?; - self.access - .has_component_write(id) - // SAFETY: - // - We have write access - // - Caller ensures `T` is a mutable component - .then(|| unsafe { self.entity.get_mut_assume_mutable() }) - .flatten() - } - - /// Retrieves the change ticks for the given component. This can be useful for implementing change - /// detection in custom runtimes. - #[inline] - pub fn get_change_ticks(&self) -> Option { - self.as_readonly().get_change_ticks::() - } - - /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change - /// detection in custom runtimes. - /// - /// **You should prefer to use the typed API [`Self::get_change_ticks`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - #[inline] - pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option { - self.as_readonly().get_change_ticks_by_id(component_id) - } - - /// Gets the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`FilteredEntityMut::get`], this returns a raw pointer to the component, - /// which is only valid while the [`FilteredEntityMut`] is alive. - #[inline] - pub fn get_by_id(&self, component_id: ComponentId) -> Option> { - self.as_readonly().get_by_id(component_id) - } - - /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get_mut`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`FilteredEntityMut::get_mut`], this returns a raw pointer to the component, - /// which is only valid while the [`FilteredEntityMut`] is alive. - #[inline] - pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option> { - // SAFETY: we use a mutable reference to self, so we cannot use the `FilteredEntityMut` to access - // another component - unsafe { self.get_mut_by_id_unchecked(component_id) } - } - - /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity. - /// - /// **You should prefer to use the typed API [`Self::get_mut`] where possible and only - /// use this in cases where the actual component types are not known at - /// compile time.** - /// - /// Unlike [`FilteredEntityMut::get_mut`], this returns a raw pointer to the component, - /// which is only valid while the [`FilteredEntityMut`] is alive. - /// - /// This only requires `&self`, and so may be used to get mutable access to multiple components. - /// - /// # Safety - /// - /// No other references to the same component may exist at the same time as the returned reference. - /// - /// # See also - /// - /// - [`get_mut_by_id`](Self::get_mut_by_id) for the safe version. - #[inline] - pub unsafe fn get_mut_by_id_unchecked( - &self, - component_id: ComponentId, - ) -> Option> { - self.access - .has_component_write(component_id) - // SAFETY: We have permission to access the component mutable - // and we promise to not create other references to the same component - .then(|| unsafe { self.entity.get_mut_by_id(component_id).ok() }) - .flatten() - } - - /// Returns the source code location from which this entity has last been spawned. - pub fn spawned_by(&self) -> MaybeLocation { - self.entity.spawned_by() - } - - /// Returns the [`Tick`] at which this entity has been spawned. - pub fn spawn_tick(&self) -> Tick { - self.entity.spawn_tick() - } } -impl<'a> TryFrom> for EntityRef<'a> { +impl<'w> TryFrom> for EntityRef<'w> { type Error = TryFromFilteredError; #[inline] - fn try_from(entity: FilteredEntityMut<'a, '_>) -> Result { + fn try_from(entity: FilteredEntityMut<'w, '_>) -> Result { entity.into_readonly().try_into_all() } } -impl<'a> TryFrom<&'a FilteredEntityMut<'_, '_>> for EntityRef<'a> { +impl<'w> TryFrom<&'w FilteredEntityMut<'_, '_>> for EntityRef<'w> { type Error = TryFromFilteredError; #[inline] - fn try_from(entity: &'a FilteredEntityMut<'_, '_>) -> Result { + fn try_from(entity: &'w FilteredEntityMut<'_, '_>) -> Result { entity.as_readonly().try_into_all() } } -impl<'a> TryFrom> for EntityMut<'a> { +impl<'w> TryFrom> for EntityMut<'w> { type Error = TryFromFilteredError; - fn try_from(entity: FilteredEntityMut<'a, '_>) -> Result { + #[inline] + fn try_from(entity: FilteredEntityMut<'w, '_>) -> Result { entity.try_into_all() } } -impl<'a> TryFrom<&'a mut FilteredEntityMut<'_, '_>> for EntityMut<'a> { +impl<'w> TryFrom<&'w mut FilteredEntityMut<'_, '_>> for EntityMut<'w> { type Error = TryFromFilteredError; #[inline] - fn try_from(entity: &'a mut FilteredEntityMut<'_, '_>) -> Result { + fn try_from(entity: &'w mut FilteredEntityMut<'_, '_>) -> Result { entity.reborrow().try_into_all() } } -impl<'w, 's> From<&'w mut FilteredEntityMut<'_, 's>> for FilteredEntityMut<'w, 's> { - #[inline] - fn from(entity: &'w mut FilteredEntityMut<'_, 's>) -> Self { - entity.reborrow() - } -} - -impl<'w, 's> From> for FilteredEntityRef<'w, 's> { - #[inline] - fn from(entity: FilteredEntityMut<'w, 's>) -> Self { - entity.into_readonly() - } -} - -impl<'w, 's> From<&'w FilteredEntityMut<'_, 's>> for FilteredEntityRef<'w, 's> { - #[inline] - fn from(entity: &'w FilteredEntityMut<'_, 's>) -> Self { - entity.as_readonly() - } -} - -impl PartialEq for FilteredEntityMut<'_, '_> { - fn eq(&self, other: &Self) -> bool { - self.entity() == other.entity() - } -} - -impl Eq for FilteredEntityMut<'_, '_> {} - -impl PartialOrd for FilteredEntityMut<'_, '_> { - /// [`FilteredEntityMut`]'s comparison trait implementations match the underlying [`Entity`], - /// and cannot discern between different worlds. - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for FilteredEntityMut<'_, '_> { - fn cmp(&self, other: &Self) -> Ordering { - self.entity().cmp(&other.entity()) - } -} - -impl Hash for FilteredEntityMut<'_, '_> { - fn hash(&self, state: &mut H) { - self.entity().hash(state); - } -} - -impl ContainsEntity for FilteredEntityMut<'_, '_> { - fn entity(&self) -> Entity { - self.id() - } -} - -// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity. -unsafe impl EntityEquivalent for FilteredEntityMut<'_, '_> {} - -/// Error type returned by [`TryFrom`] conversions from filtered entity types -/// ([`FilteredEntityRef`]/[`FilteredEntityMut`]) to full-access entity types -/// ([`EntityRef`]/[`EntityMut`]). +/// Error type returned by [`TryFrom`] conversions from [`EntityRef`]/[`EntityMut`] +/// entity reference types with [`Filtered`] access to ones with [`All`] access. #[derive(Error, Debug)] pub enum TryFromFilteredError { /// Error indicating that the filtered entity does not have read access to diff --git a/crates/bevy_ecs/src/world/entity_access/mod.rs b/crates/bevy_ecs/src/world/entity_access/mod.rs index cc1bd85449761..21b8a9ce65f66 100644 --- a/crates/bevy_ecs/src/world/entity_access/mod.rs +++ b/crates/bevy_ecs/src/world/entity_access/mod.rs @@ -1,3 +1,5 @@ +mod all; +mod as_access; mod component_fetch; mod entity_mut; mod entity_ref; @@ -6,6 +8,7 @@ mod except; mod filtered; mod world_mut; +pub use as_access::*; pub use component_fetch::*; pub use entity_mut::*; pub use entity_ref::*; @@ -752,7 +755,7 @@ mod tests { assert!(e.get::().is_some()); assert!(e.get_ref::().is_some()); assert!(e.get_change_ticks::().is_some()); - assert!(e.get_by_id(a_id).is_some()); + assert!(e.get_by_id(a_id).is_ok()); assert!(e.get_change_ticks_by_id(a_id).is_some()); } @@ -766,7 +769,7 @@ mod tests { assert!(e.get::().is_none()); assert!(e.get_ref::().is_none()); assert!(e.get_change_ticks::().is_none()); - assert!(e.get_by_id(a_id).is_none()); + assert!(e.get_by_id(a_id).is_err()); assert!(e.get_change_ticks_by_id(a_id).is_none()); } @@ -781,8 +784,8 @@ mod tests { assert!(e.get_ref::().is_some()); assert!(e.get_mut::().is_some()); assert!(e.get_change_ticks::().is_some()); - assert!(e.get_by_id(a_id).is_some()); - assert!(e.get_mut_by_id(a_id).is_some()); + assert!(e.get_by_id(a_id).is_ok()); + assert!(e.get_mut_by_id(a_id).is_ok()); assert!(e.get_change_ticks_by_id(a_id).is_some()); } @@ -797,8 +800,8 @@ mod tests { assert!(e.get_ref::().is_none()); assert!(e.get_mut::().is_none()); assert!(e.get_change_ticks::().is_none()); - assert!(e.get_by_id(a_id).is_none()); - assert!(e.get_mut_by_id(a_id).is_none()); + assert!(e.get_by_id(a_id).is_err()); + assert!(e.get_mut_by_id(a_id).is_err()); assert!(e.get_change_ticks_by_id(a_id).is_none()); } diff --git a/crates/bevy_ecs/src/world/entity_access/world_mut.rs b/crates/bevy_ecs/src/world/entity_access/world_mut.rs index 10e5dae4765db..08b6806f9ba0b 100644 --- a/crates/bevy_ecs/src/world/entity_access/world_mut.rs +++ b/crates/bevy_ecs/src/world/entity_access/world_mut.rs @@ -18,7 +18,7 @@ use crate::{ storage::{SparseSets, Table}, system::IntoObserverSystem, world::{ - error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, ComponentEntry, + error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, All, ComponentEntry, DynamicComponentFetch, EntityMut, EntityRef, FilteredEntityMut, FilteredEntityRef, Mut, OccupiedComponentEntry, Ref, VacantComponentEntry, World, }, @@ -131,11 +131,12 @@ impl<'w> EntityWorldMut<'w> { /// Consumes `self` and returns read-only access to all of the entity's /// components, with the world `'w` lifetime. + #[inline] pub fn into_readonly(self) -> EntityRef<'w> { // SAFETY: // - We have exclusive access to the entire world. // - Consuming `self` ensures no mutable accesses are active. - unsafe { EntityRef::new(self.into_unsafe_entity_cell()) } + unsafe { EntityRef::new(self.into_unsafe_entity_cell(), All) } } /// Gets read-only access to all of the entity's components. @@ -144,16 +145,17 @@ impl<'w> EntityWorldMut<'w> { // SAFETY: // - We have exclusive access to the entire world. // - `&self` ensures no mutable accesses are active. - unsafe { EntityRef::new(self.as_unsafe_entity_cell_readonly()) } + unsafe { EntityRef::new(self.as_unsafe_entity_cell_readonly(), All) } } /// Consumes `self` and returns non-structural mutable access to all of the /// entity's components, with the world `'w` lifetime. + #[inline] pub fn into_mutable(self) -> EntityMut<'w> { // SAFETY: // - We have exclusive access to the entire world. // - Consuming `self` ensures there are no other accesses. - unsafe { EntityMut::new(self.into_unsafe_entity_cell()) } + unsafe { EntityMut::new(self.into_unsafe_entity_cell(), All) } } /// Gets non-structural mutable access to all of the entity's components. @@ -162,7 +164,7 @@ impl<'w> EntityWorldMut<'w> { // SAFETY: // - We have exclusive access to the entire world. // - `&mut self` ensures there are no other accesses. - unsafe { EntityMut::new(self.as_unsafe_entity_cell()) } + unsafe { EntityMut::new(self.as_unsafe_entity_cell(), All) } } /// Returns the [ID](Entity) of the current entity. @@ -614,8 +616,7 @@ impl<'w> EntityWorldMut<'w> { /// If the entity has been despawned while this `EntityWorldMut` is still alive. #[inline] pub fn into_mut>(self) -> Option> { - // SAFETY: consuming `self` implies exclusive access - unsafe { self.into_unsafe_entity_cell().get_mut() } + self.into_mutable().into_mut() } /// Consumes `self` and gets mutable access to the component of type `T` @@ -631,8 +632,7 @@ impl<'w> EntityWorldMut<'w> { /// - `T` must be a mutable component #[inline] pub unsafe fn into_mut_assume_mutable(self) -> Option> { - // SAFETY: consuming `self` implies exclusive access - unsafe { self.into_unsafe_entity_cell().get_mut_assume_mutable() } + self.into_mutable().into_mut_assume_mutable() } /// Gets a reference to the resource of the given type diff --git a/crates/bevy_ecs/src/world/entity_fetch.rs b/crates/bevy_ecs/src/world/entity_fetch.rs index 457f176d0457d..09e4b359d0336 100644 --- a/crates/bevy_ecs/src/world/entity_fetch.rs +++ b/crates/bevy_ecs/src/world/entity_fetch.rs @@ -5,8 +5,8 @@ use crate::{ entity::{Entity, EntityHashMap, EntityHashSet, EntityNotSpawnedError}, error::Result, world::{ - error::EntityMutableFetchError, unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, - EntityWorldMut, + error::EntityMutableFetchError, unsafe_world_cell::UnsafeWorldCell, All, EntityMut, + EntityRef, EntityWorldMut, }, }; @@ -207,7 +207,7 @@ unsafe impl WorldEntityFetch for Entity { ) -> Result, EntityNotSpawnedError> { 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) }) + Ok(unsafe { EntityRef::new(ecell, All) }) } #[inline] @@ -229,7 +229,7 @@ unsafe impl WorldEntityFetch for Entity { ) -> 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) }) + Ok(unsafe { EntityMut::new(ecell, All) }) } } @@ -288,7 +288,7 @@ unsafe impl WorldEntityFetch for &'_ [Entity; 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) }); + *r = MaybeUninit::new(unsafe { EntityRef::new(ecell, All) }); } // SAFETY: Each item was initialized in the loop above. @@ -315,7 +315,7 @@ unsafe impl WorldEntityFetch for &'_ [Entity; 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) }); + *r = MaybeUninit::new(unsafe { EntityMut::new(ecell, All) }); } // SAFETY: Each item was initialized in the loop above. @@ -353,7 +353,7 @@ unsafe impl WorldEntityFetch for &'_ [Entity] { 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) }); + refs.push(unsafe { EntityRef::new(ecell, All) }); } Ok(refs) @@ -377,7 +377,7 @@ unsafe impl WorldEntityFetch for &'_ [Entity] { 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) }); + refs.push(unsafe { EntityMut::new(ecell, All) }); } Ok(refs) @@ -412,7 +412,7 @@ unsafe impl WorldEntityFetch for &'_ EntityHashSet { 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) }); + refs.insert(id, unsafe { EntityRef::new(ecell, All) }); } Ok(refs) } @@ -426,7 +426,7 @@ unsafe impl WorldEntityFetch for &'_ EntityHashSet { 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) }); + refs.insert(id, unsafe { EntityMut::new(ecell, All) }); } Ok(refs) } diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 8157b03a61afc..2882e84d0d3fe 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -25,9 +25,9 @@ pub use crate::{ pub use bevy_ecs_macros::FromWorld; pub use deferred_world::DeferredWorld; pub use entity_access::{ - ComponentEntry, DynamicComponentFetch, EntityMut, EntityMutExcept, EntityRef, EntityRefExcept, - EntityWorldMut, FilteredEntityMut, FilteredEntityRef, OccupiedComponentEntry, - TryFromFilteredError, UnsafeFilteredEntityMut, VacantComponentEntry, + All, AsAccess, ComponentEntry, DynamicComponentFetch, EntityMut, EntityMutExcept, EntityRef, + EntityRefExcept, EntityWorldMut, Except, Filtered, FilteredEntityMut, FilteredEntityRef, + OccupiedComponentEntry, TryFromFilteredError, UnsafeFilteredEntityMut, VacantComponentEntry, }; pub use entity_fetch::{EntityFetcher, WorldEntityFetch}; pub use filtered_resource::*; diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index cae3f5d333db7..2154147c6ee9c 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -19,7 +19,7 @@ use crate::{ query::{DebugCheckedUnwrap, QueryAccessError, ReleaseStateQueryData}, resource::Resource, storage::{ComponentSparseSet, Storages, Table}, - world::RawCommandQueue, + world::{AsAccess, RawCommandQueue}, }; use bevy_platform::sync::atomic::Ordering; use bevy_ptr::Ptr; @@ -806,16 +806,22 @@ impl<'w> UnsafeEntityCell<'w> { } /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component - /// - no other mutable references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] - pub unsafe fn get(self) -> Option<&'w T> { + pub unsafe fn get(self, access: impl AsAccess) -> Option<&'w T> { let component_id = self.world.components().get_valid_id(TypeId::of::())?; + + if !access.has_component_read(component_id) { + return None; + } + // SAFETY: // - `storage_type` is correct (T component_id + T::STORAGE_TYPE) // - `location` is valid - // - proper aliasing is promised by caller + // - proper world access is promised by caller unsafe { get_component( self.world, @@ -830,19 +836,25 @@ impl<'w> UnsafeEntityCell<'w> { } /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component - /// - no other mutable references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] - pub unsafe fn get_ref(self) -> Option> { + pub unsafe fn get_ref(self, access: impl AsAccess) -> Option> { + let component_id = self.world.components().get_valid_id(TypeId::of::())?; + + if !access.has_component_read(component_id) { + return None; + } + let last_change_tick = self.last_run; let change_tick = self.this_run; - let component_id = self.world.components().get_valid_id(TypeId::of::())?; // SAFETY: // - `storage_type` is correct (T component_id + T::STORAGE_TYPE) // - `location` is valid - // - proper aliasing is promised by caller + // - proper world access is promised by caller unsafe { get_component_and_ticks( self.world, @@ -863,13 +875,21 @@ impl<'w> UnsafeEntityCell<'w> { /// detection in custom runtimes. /// /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component - /// - no other mutable references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] - pub unsafe fn get_change_ticks(self) -> Option { + pub unsafe fn get_change_ticks( + self, + access: impl AsAccess, + ) -> Option { let component_id = self.world.components().get_valid_id(TypeId::of::())?; + if !access.has_component_read(component_id) { + return None; + } + // SAFETY: // - entity location is valid // - proper world access is promised by caller @@ -892,19 +912,26 @@ impl<'w> UnsafeEntityCell<'w> { /// compile time.** /// /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component - /// - no other mutable references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] pub unsafe fn get_change_ticks_by_id( &self, + access: impl AsAccess, component_id: ComponentId, ) -> Option { + if !access.has_component_read(component_id) { + return None; + } + let info = self.world.components().get_info(component_id)?; // SAFETY: // - entity location and entity is valid // - world access is immutable, lifetime tied to `&self` // - the storage type provided is correct for T + // - proper world access is promised by caller unsafe { get_ticks( self.world, @@ -917,36 +944,48 @@ impl<'w> UnsafeEntityCell<'w> { } /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component mutably - /// - no other references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the write + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] - pub unsafe fn get_mut>(self) -> Option> { + pub unsafe fn get_mut>( + self, + access: impl AsAccess, + ) -> Option> { // SAFETY: // - trait bound `T: Component` ensures component is mutable - // - same safety requirements - unsafe { self.get_mut_assume_mutable() } + // - proper world access is promised by caller + unsafe { self.get_mut_assume_mutable(access) } } /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component mutably - /// - no other references to the component exist at the same time - /// - the component `T` is mutable + /// + /// Caller must ensure that: + /// - The provided [`AsAccess`] does not exceed the write permissions of + /// `self` in a way that would violate Rust's aliasing rules, including + /// via copies of `self` or other indirect means. + /// - The component `T` is mutable. #[inline] - pub unsafe fn get_mut_assume_mutable(self) -> Option> { - // SAFETY: same safety requirements - unsafe { self.get_mut_using_ticks_assume_mutable(self.last_run, self.this_run) } + pub unsafe fn get_mut_assume_mutable( + self, + access: impl AsAccess, + ) -> Option> { + // SAFETY: proper world access is promised by caller + unsafe { self.get_mut_using_ticks_assume_mutable(access, self.last_run, self.this_run) } } /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component mutably - /// - no other references to the component exist at the same time - /// - The component `T` is mutable + /// + /// Caller must ensure that: + /// - The provided [`AsAccess`] does not exceed the write permissions of + /// `self` in a way that would violate Rust's aliasing rules, including + /// via copies of `self` or other indirect means. + /// - The component `T` is mutable. #[inline] pub(crate) unsafe fn get_mut_using_ticks_assume_mutable( &self, + access: impl AsAccess, last_change_tick: Tick, change_tick: Tick, ) -> Option> { @@ -954,10 +993,14 @@ impl<'w> UnsafeEntityCell<'w> { let component_id = self.world.components().get_valid_id(TypeId::of::())?; + if !access.has_component_write(component_id) { + return None; + } + // SAFETY: // - `storage_type` is correct // - `location` is valid - // - aliasing rules are ensured by caller + // - proper world access is promised by caller unsafe { get_component_and_ticks( self.world, @@ -979,7 +1022,7 @@ impl<'w> UnsafeEntityCell<'w> { /// /// # Safety /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the queried data immutably + /// - `self` has permission to access the queried data immutably /// - no mutable references to the queried data exist at the same time /// - The `QueryData` does not provide aliasing mutable references to the same component. pub(crate) unsafe fn get_components( @@ -1032,13 +1075,25 @@ impl<'w> UnsafeEntityCell<'w> { /// which is only valid while the `'w` borrow of the lifetime is active. /// /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component - /// - no other mutable references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the read + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] - pub unsafe fn get_by_id(self, component_id: ComponentId) -> Option> { + pub unsafe fn get_by_id( + self, + access: impl AsAccess, + component_id: ComponentId, + ) -> Option> { + if !access.has_component_read(component_id) { + return None; + } + let info = self.world.components().get_info(component_id)?; - // SAFETY: entity_location is valid, component_id is valid as checked by the line above + // SAFETY: + // - entity_location is valid, + // - component_id is valid as checked by the line above + // - proper world access is promised by caller unsafe { get_component( self.world, @@ -1057,16 +1112,22 @@ impl<'w> UnsafeEntityCell<'w> { /// use this in cases where the actual types are not known at compile time.** /// /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component mutably - /// - no other references to the component exist at the same time + /// + /// Caller must ensure the provided [`AsAccess`] does not exceed the write + /// permissions of `self` in a way that would violate Rust's aliasing rules, + /// including via copies of `self` or other indirect means. #[inline] pub unsafe fn get_mut_by_id( self, + access: impl AsAccess, component_id: ComponentId, ) -> Result, GetEntityMutByIdError> { self.world.assert_allows_mutable_access(); + if !access.has_component_write(component_id) { + return Err(GetEntityMutByIdError::ComponentNotFound); + } + let info = self .world .components() @@ -1078,7 +1139,10 @@ impl<'w> UnsafeEntityCell<'w> { return Err(GetEntityMutByIdError::ComponentIsImmutable); } - // SAFETY: entity_location is valid, component_id is valid as checked by the line above + // SAFETY: + // - entity_location is valid + // - component_id is valid as checked by the line above + // - proper world access is promised by caller unsafe { get_component_and_ticks( self.world, @@ -1104,24 +1168,34 @@ impl<'w> UnsafeEntityCell<'w> { /// use this in cases where the actual types are not known at compile time.** /// /// # Safety - /// It is the caller's responsibility to ensure that - /// - the [`UnsafeEntityCell`] has permission to access the component mutably - /// - no other references to the component exist at the same time - /// - the component `T` is mutable + /// + /// Caller must ensure that: + /// - The provided [`AsAccess`] does not exceed the write permissions of + /// `self` in a way that would violate Rust's aliasing rules, including + /// via copies of `self` or other indirect means. + /// - The component `T` is mutable. #[inline] pub unsafe fn get_mut_assume_mutable_by_id( self, + access: impl AsAccess, component_id: ComponentId, ) -> Result, GetEntityMutByIdError> { self.world.assert_allows_mutable_access(); + if !access.has_component_write(component_id) { + return Err(GetEntityMutByIdError::ComponentNotFound); + } + let info = self .world .components() .get_info(component_id) .ok_or(GetEntityMutByIdError::InfoNotFound)?; - // SAFETY: entity_location is valid, component_id is valid as checked by the line above + // SAFETY: + // - entity_location is valid + // - component_id is valid as checked by the line above + // - proper world access is promised by caller unsafe { get_component_and_ticks( self.world, @@ -1298,6 +1372,8 @@ impl ContainsEntity for UnsafeEntityCell<'_> { #[cfg(test)] mod tests { + use crate::world::All; + use super::*; #[test] @@ -1333,6 +1409,6 @@ mod tests { let world_cell = world.as_unsafe_world_cell_readonly(); let entity_cell = world_cell.get_entity(entity).unwrap(); // SAFETY: this invalid usage will be caught by a runtime panic. - let _ = unsafe { entity_cell.get_mut::() }; + let _ = unsafe { entity_cell.get_mut::(All) }; } } diff --git a/examples/stress_tests/many_components.rs b/examples/stress_tests/many_components.rs index 60ace001f5333..0620d6de19d35 100644 --- a/examples/stress_tests/many_components.rs +++ b/examples/stress_tests/many_components.rs @@ -65,7 +65,7 @@ fn base_system(access_components: In>, mut query: Query(); diff --git a/release-content/migration-guides/entity_deduplication.md b/release-content/migration-guides/entity_deduplication.md new file mode 100644 index 0000000000000..d9dde72bfbbf7 --- /dev/null +++ b/release-content/migration-guides/entity_deduplication.md @@ -0,0 +1,35 @@ +--- +title: "`UnsafeEntityCell` functions now have an `AsAccess` parameter" +pull_requests: [22538] +--- + +The following functions now return a `Result` with a proper error, instead of an +`Option`. Handle accordingly. + +- `FilteredEntityRef::get_by_id` +- `FilteredEntityMut::get_by_id` +- `FilteredEntityMut::get_mut_by_id` +- `FilteredEntityMut::get_mut_by_id_unchecked` +- `EntityRefExcept::get_by_id` +- `EntityMutExcept::get_by_id` +- `EntityMutExcept::get_mut_by_id` + +The following functions now take an `AsAccess` as an additional argument. +You should pass an access type that most closely matches your access patterns, +and ensure it abides by Rust aliasing rules. + +- `UnsafeEntityCell::get` +- `UnsafeEntityCell::get_ref` +- `UnsafeEntityCell::get_change_ticks` +- `UnsafeEntityCell::get_change_ticks_by_id` +- `UnsafeEntityCell::get_mut` +- `UnsafeEntityCell::get_mut_assume_mutable` +- `UnsafeEntityCell::get_by_id` +- `UnsafeEntityCell::get_mut_by_id` +- `UnsafeEntityCell::get_mut_assume_mutable_by_id` + +For example, if your cell can access all components without violating aliasing +rules, use `All`. If your cell can only access a specific set of +components without violating aliasing rules, consider using `Filtered` or `Except`. +If you are able to validate externally that you won't violate aliasing +rules by accessing a particular component, you may use `All`.