# EntityPtrs and where to find them
Author(s): @doot @bushRAT @Victoron
Contributor(s): @quartermeister @Diddykonga
## Working Group Goals
- Reduce code duplication within the "Entity pointer" APIs
- Minimize breaking changes where possible (these are heavily used APIs)
- Ensure the main entity pointer types and the filtered variants provide consistent access to operations on an entity pointer.
- Current APIs are missing various operations for the filtered variants that are present on the main ones.
## Unresolved Questions
- [ ] Should `Shared`/`Exclusive` capabilities be renamed?
- [ ] Should `EntityPtr` be renamed to `EntityCell`?
- [ ] What performance regressions (if any) do we encounter by switching `&mut World` to `UnsafeWorldCell` for `EntityWorldMut`?
- [ ] Do we see any performance hits with `Full` and `Global` when calling `Scope::can_read/can_write`? They *should* inline into a no-op, but we should check.
- [ ] Should we remove `UnsafeEntityCell` and inline its logic into `EntityPtr`?
- [ ] Additionally, should we introduce a new `Unsafe` capability as a replacement? It would be a `Copy`able pointer that can (unsafely) give out mutable references.
- [ ] Should the `Capability` be stored directly on the `EntityPtr`, as opposed to `PhantomData`? This would enable a `EntityPtr::new(cell, capability, scope`) style constructor.
- [ ] Should `EntityRef`/`EntityMut`'s scope type parameter be un-defaulted and aliases added for `Full`: `FullEntityRef`/`FullEntityMut`?
- [ ] Should we remove the following functions from `World`, given they have equivalents through entity references? `World::get`, `World::get_mut`, `World::get_by_id`, `World::get_mut_by_id`, `World::inspect_entity`, `World::despawn`, `World::try_despawn`.
- [ ] Should we keep `EntityWorldMut` as a separate type? If we unify it, we will likely need to add a function to the `Scope` trait to update the location for all `EntityPtr` functions. For non-global `Scope`s, this would be implemented as a no-op.
- [ ] Should `World::get_entity` family of functions return `EntityWorldRef`s instead of `EntityRef`s?
- [ ] Since `EntityFetcher` now exists, should we add a scope for "can access itself and all other entities"? This would be a smaller scope than `Global`'s "can access itself and the whole world".
- [ ] Should we add an `And<(A, B, ...)>` scope combinator that performs boolean AND on all of the contained scopes?
- [ ] Should we rename the `Full` scope to `All`?
## Capabilities
Capabilities describe what you can _do_ to data referenced by an `EntityPtr`. The `Shared` capability allows for shared, or "read-only", access. This is analagous to Rust's `&T` reference type. Following from this, the `Exclusive` capability allows for exclusive, or "mutable", access. Again, analogous to Rust's `&mut T` reference type.
## Scopes
Scopes describe _what_ you can access with an `EntityPtr`. The typical scope for an `EntityPtr` is `Full`, permitting visibility over all components owned by this entity. `Global` is a wider scope, allowing visibility over the entire `World` that this entity lives in. In the opposite direction, `Except`, `Only`, and `Partial` give subsets of `Full` access. `Except` is `Full` scope, _except_ a given `Bundle` `B`. `Only` is the inverse of `Except`, providing access _only_ to a given `Bundle` `B`. Finally, `Partial` is a more complex subset of `Full`, where the exact items you have scope over is controlled at runtime via an `Access<ComponentId>`.
### Q: Why is `World` access a scope and not a capability?
If `World` access were a `Capability`, it would interact weirdly with filters (which are scopes). For example, if you have world capability, but you're filtered to only access `Foo`, then you could access the component `Bar` by getting a world reference and said entity directly. So there's no reason to give out a `EntityPtr<Global, Only<Bundle>>` or make it constructible in the first place.
In Rust terms, we can say that Capabilities define what *type* of borrow an entity pointer is, while Scopes define how *big or small* the borrow is: from just a few specific components, to the whole entity, or the whole `World`.
## Scopes vs Capabilities
If we were to map out how scopes and capabilities fit into the types that exist in Bevy today, it would follow as such:
- `EntityRef` is a `Shared` pointer with `Full` access to the entity's components.
- `EntityMut` is an `Exclusive` pointer with `Full` access to the entity's components.
- `EntityWorldMut` is an `Exclusive` pointer with `Global` access to the entity's components and the `World` at large.
- `FilteredEntityRef` is a `Shared` pointer with `Partial` access to the entity's components, as defined by an `Access<ComponentId>`.
- `FilteredEntityMut` likewise is an `Exclusive` pointer with `Partial` access to the entity's components.
- `EntityRefExcept<B>` is a `Shared` pointer with access to all of the entity's components `Except` the ones included in the `Bundle` `B`.
- `EntityMutExcept<B>` likewise is an `Exclusive` pointer with access to all of the entity's components `Except` the ones included in the `Bundle` `B`.
A table is provided below to see the different types altogether.
Scopes are across the top, while Capabilities are along the left-hand side.
| | Full | Global | Except | Only | Partial |
|-----------|-----------|----------------|-----------------|---------------|-------------------|
| Shared | EntityRef | EntityWorldRef | EntityRefExcept | EntityRefOnly | FilteredEntityRef |
| Exclusive | EntityMut | EntityWorldMut | EntityMutExcept | EntityMutOnly | FilteredEntityMut |
## Proposed breaking changes
- `EntityRef::get` and related functions now return references with lifetime `'_` instead of `'w`. Use the `into_x` family of functions instead if `'w` data is required.
- *(optional)* Rename `EntityWorldMut` -> `EntityMutWorld`.
- Reason: `World` is now more like a "scope" rather than an access level, so would be more aptly named Entity(Capability)(Scope). Note that `Full` is considered the "default" scope.
## Public API Definition
```rust
/// A pointer to an [`Entity`] with access to some or all of its components,
/// as determined by the [`Scope`] `S`. The operations available to the
/// user are determined by the [`Capability`] `C`. (i.e. whether the
/// entity is read-only or mutable).
///
/// # Capabilities
///
/// Capabilities describe what you can _do_ to data referenced by an entity
/// pointer. The [`Shared`] capability allows for shared, or "read-only",
/// access. This is analagous to Rust's `&T` reference type. Following from
/// this, the [`Exclusive`] capability allows for exclusive, or "mutable",
/// access. Again, analogous to Rust's `&mut T` reference type.
///
/// # Scopes
///
/// Scopes describe _what_ you can access with an entity pointer. The typical
/// scope for an entity pointer is [`Full`], permitting visibility over all
/// components owned by this entity. [`Global`] is a wider scope, allowing
/// visibility over the entire [`World`] that this entity lives in.
///
/// In the opposite direction, [`Except`], [`Only`], and [`Partial`] give
/// subsets of [`Full`] access:
///
/// - [`Except`] provides access to all components _except_ those given in
/// the [`Bundle`] `B`.
/// - [`Only`] is the inverse of [`Except`], providing access _only_ to a
/// given [`Bundle`] `B`.
/// - [`Partial`] is a more complex subset of [`Full`], where the exact items
/// available are defined at runtime via an [`Access<ComponentId>`].
///
/// # Table of Scopes vs Capabilities
///
/// Scopes are across the top, while Capabilities are along the left-hand side.
///
/// | | Full | Global | Except | Only | Partial |
/// |-----------|-----------|----------------|-----------------|---------------|-------------------|
/// | Shared | EntityRef | EntityWorldRef | EntityRefExcept | EntityRefOnly | FilteredEntityRef |
/// | Exclusive | EntityMut | EntityWorldMut | EntityMutExcept | EntityMutOnly | FilteredEntityMut |
pub struct EntityPtr<'w, C: Capability, S: Scope = Full> {
cell: UnsafeEntityCell<'w>,
scope: S,
_capability: PhantomData<C>,
}
impl<'w, C: Capability, S: Scope> EntityPtr<'w, C, S> {
pub fn as_readonly(&self) -> EntityPtr<'_, Shared, &S>;
pub fn into_readonly(self) -> EntityPtr<'w, Shared, S>;
pub fn scope(&self) -> &S;
pub fn into_scope(self) -> S;
pub fn id(&self) -> Entity;
pub fn location(&self) -> EntityLocation;
pub fn archetype(&self) -> &Archetype;
pub fn contains<T: Component>(&self) -> bool;
pub fn contains_id(&self, component: ComponentId) -> bool;
pub fn contains_type_id(&self, type_id: TypeId) -> bool;
pub fn get<T: Component>(&self) -> Option<&'_ T>;
pub fn get_ref<T: Component>(&self) -> Option<Ref<'_, T>>;
pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks>;
pub fn get_change_ticks_by_id(&self, component: ComponentId)
-> Option<ComponentTicks>;
pub fn get_by_id<F: DynamicComponentFetch>(&self, component_ids: F)
-> Result<F::Ref<'_>, EntityComponentError>;
pub fn components<Q: ReadOnlyQueryData>(&self) -> Q::Item<'_>;
pub fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>>;
pub fn into_borrow<T: Component>(self) -> Option<&'w T>;
pub fn into_ref<T: Component>(self) -> Option<Ref<'w, T>>;
pub fn into_borrow_by_id<F: DynamicComponentFetch>(self, component_ids: F)
-> Result<F::Ref<'w>, EntityComponentError>;
pub fn into_components<Q: ReadOnlyQueryData>(self) -> Q::Item<'w>;
pub fn try_into_components<Q: ReadOnlyQueryData>(self) -> Option<Q::Item<'w>>;
}
impl<'w, S: Scope> EntityPtr<'w, Shared, S> {
pub(crate) unsafe fn new_shared(cell: UnsafeEntityCell<'w>, scope: S) -> Self;
}
impl<'w, S: Scope> EntityPtr<'w, Exclusive, S> {
pub(crate) unsafe fn new_exclusive(cell: UnsafeEntityCell<'w>, scope: S) -> Self;
pub fn reborrow(&mut self) -> EntityPtr<'_, Exclusive, &S>;
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>>;
pub fn get_mut_by_id<F: DynamicComponentFetch>(&mut self, component_ids: F)
-> Result<F::Mut<'_>, EntityComponentError>;
pub unsafe fn get_mut_by_id_unchecked<F: DynamicComponentFetch>(
&self,
component_ids: F
) -> Result<F::Mut<'_>, EntityComponentError>;
pub fn into_mut<T: Component>(self) -> Option<Mut<'w, T>>;
pub fn into_mut_by_id<F: DynamicComponentFetch>(self, component_ids: F)
-> Result<F::Mut<'w>, EntityComponentError>;
}
/// Both [`Shared`] and [`Exclusive`] capabilities have access to these
/// functions.
impl<'w, C: Capability> EntityPtr<'w, C, Global> {
pub fn world(&self) -> &World;
pub fn into_world(self) -> &'w World;
pub fn downgrade(&self) -> EntityPtr<'_, C, Full>;
pub fn downgrade_into(self) -> EntityPtr<'w, C, Full>;
}
impl<'w> EntityPtr<'w, Exclusive, Global> {
pub unsafe fn world_mut(&mut self) -> &mut World;
pub fn into_world_mut(self) -> &'w mut World;
pub fn world_scope<U>(&mut self, f: impl FnOnce(&mut World) -> U) -> U;
pub fn insert<T: Bundle>(&mut self, bundle: T);
pub fn insert_if_new<T: Bundle>(&mut self, bundle: T) -> &mut Self;
pub unsafe fn insert_by_id(
&mut self,
component_id: ComponentId,
component: OwningPtr<'_>
) -> &mut Self;
pub unsafe fn insert_by_ids<'a, I: Iterator<Item = OwningPtr<'a>>>(
&mut self,
component_ids: &[ComponentId],
iter_components: I
) -> &mut Self;
pub fn take<T: Bundle>(&mut self) -> Option<T>;
pub fn remove<T: Bundle>(&mut self) -> &mut Self;
pub fn remove_with_requires<T: Bundle>(&mut self) -> &mut Self;
pub fn retain<T: Bundle>(&mut self) -> &mut Self;
pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self;
pub fn clear(&mut self) -> &mut Self;
pub fn despawn(self);
pub fn flush(self) -> Entity;
pub fn update_location(&mut self);
pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T>;
pub fn trigger(&mut self, event: impl Event) -> &mut Self;
pub fn observe<E: Event, B: Bundle, M>(
&mut self,
observer: impl IntoObserverSystem<E, B, M>
) -> &mut Self;
}
impl<'w, C: Capability> EntityPtr<'w, C, Full> {
pub fn split<B: Bundle>(self)
-> (EntityPtr<'w, C, Only<B>>, EntityPtr<'w, C, Except<B>>);
pub fn split_by(self, access: Access<ComponentId>)
-> (EntityPtr<'w, C, Partial>, EntityPtr<'w, C, Partial>);
}
impl<'w, C: Capability, B: Bundle> EntityPtr<'w, C, Except<B>> {
pub fn split<C: Bundle>(self)
-> (EntityPtr<'w, C, Only<C>>, EntityPtr<'w, C, Except<(B, C)>);
}
/// [`EntityPtr`]s with a [`Clone`]able [`Scope`] that only have permission
/// to read components can be [`Clone`]d.
impl<S: Scope + Clone> Clone for EntityPtr<'_, Shared, S> {
fn clone(&self) -> Self {
Self {
cell: self.cell,
scope: self.scope.clone(),
_access: PhantomData,
}
}
}
/// [`EntityPtr`]s with a [`Copy`]able [`Scope`] that only have permission
/// to read components can be [`Copy`]'d.
impl<S: Scope + Copy> Copy for EntityPtr<'_, Shared, S> {}
/// An [`Exclusive`] entity pointer within any [`Scope`] can always be downgraded
/// into a [`Shared`] pointer in the same [`Scope`].
impl<'w, S: Scope> From<EntityPtr<'w, Exclusive, S>> for EntityPtr<'w, Shared, S> {}
impl<'w, C: Capability> TryFrom<EntityPtr<'w, C, Partial>> for EntityPtr<'w, Shared, Full> {}
impl<'a, C: Capability, S: Scope> From<&'a EntityPtr<'_, C, S>> for EntityPtr<'a, Shared, &S> {}
impl<'a, C: Capability> From<&'a EntityPtr<'_, C, Global>> for EntityPtr<'a, Shared, Full> {}
impl<'a, S: Scope> From<&'a mut EntityPtr<'_, Exclusive, S>> for EntityPtr<'a, Exclusive, &S> {}
impl<'a> From<&'a mut EntityPtr<'_, Exclusive, Global>> for EntityPtr<'a, Exclusive, Full> {}
/// An [`EntityPtr`] variant with read access to all components on an entity.
///
/// See [`EntityPtr`] for details.
pub type EntityRef<'w> = EntityPtr<'w, Shared, Full>;
/// An [`EntityPtr`] variant with mutable access to all components on an
/// entity.
///
/// See [`EntityPtr`] for details.
pub type EntityMut<'w> = EntityPtr<'w, Exclusive, Full>;
/// This [`EntityPtr`] variant provides the maximum permissions over an
/// entity, its components, and the world:
/// - The entity's components can be read and mutated.
/// - New components can be inserted onto the entity.
/// - Components can be removed from the entity.
/// - The entity can be despawned entirely.
/// - The World attached to the entity can have its command queue flushed.
///
/// See [`EntityPtr`] for further details.
pub type EntityWorldMut<'w> = EntityPtr<'w, Exclusive, Global>;
/// An [`EntityPtr`] variant with read access to some components on an
/// entity. The set of available components is determined by an
/// [`Access<ComponentId>`].
///
/// See [`EntityPtr`] for further details.
pub type FilteredEntityRef<'w> = EntityPtr<'w, Shared, Partial>;
/// An [`EntityPtr`] variant with mutable access to some components on an
/// entity. The set of available components is determined by an
/// [`Access<ComponentId>`].
///
/// See [`EntityPtr`] for further details.
pub type FilteredEntityMut<'w> = EntityPtr<'w, Exclusive, Partial>;
/// An [`EntityPtr`] variant with read access to some components on an
/// entity. The set of available components are the ones included in the
/// [`Bundle`].
///
/// See [`EntityRefExcept`] for the inverted form of this type.
/// See [`EntityPtr`] for further details.
pub type EntityRefOnly<'w, Bundle> = EntityPtr<'w, Shared, Only<Bundle>>;
/// An [`EntityPtr`] variant with mutable access to some components on an
/// entity. The set of available components are the ones included in the
/// [`Bundle`].
///
/// See [`EntityMutExcept`] for the inverted form of this type.
/// See [`EntityPtr`] for further details.
pub type EntityMutOnly<'w, Bundle> = EntityPtr<'w, Exclusive, Only<Bundle>>;
/// An [`EntityPtr`] variant with read access to some components on an
/// entity. The set of available components are the ones **NOT** included in
/// the [`Bundle`].
///
/// See [`EntityRefOnly`] for the inverted form of this type.
/// See [`EntityPtr`] for further details.
pub type EntityRefExcept<'w, Bundle> = EntityPtr<'w, Shared, Except<Bundle>>;
/// An [`EntityPtr`] variant with mutable access to some components on an
/// entity. The set of available components are the ones **NOT** included in
/// the [`Bundle`].
///
/// See [`EntityMutOnly`] for the inverted form of this type.
/// See [`EntityPtr`] for further details.
pub type EntityMutExcept<'w, Bundle> = EntityPtr<'w, Exclusive, Except<Bundle>>;
// TODO: DOCS
pub trait Capability: sealed::Capability {}
/// [`EntityPtr`] [`Capability`] used to denote that the pointer has read
/// access to an entity's components.
pub struct Shared;
impl Capability for Shared {}
/// [`EntityPtr`] [`Capability`] used to denote that it has
/// mutable access to an entity's components.
pub struct Exclusive;
impl Capability for Exclusive {}
/// TODO: DOCS
pub trait Scope: sealed::Scope {
/// Returns `true` if the given [`Component`] can be read by
/// a certain [`EntityPtr`].
fn can_read(&self, component: ComponentId) -> bool;
/// Returns `true` if the given [`Component`] can be mutated by
/// a certain [`EntityPtr`].
fn can_write(&self, component: ComponentId) -> bool;
}
impl<S: Scope> Scope for &S {
fn can_read(&self, component: ComponentId) -> bool {
(**self).can_read(component)
}
fn can_write(&self, component: ComponentId) -> bool {
(**self).can_write(component)
}
}
/// [`EntityPtr`] [`Scope`] that provides full access to an entity's components.
///
/// See [`EntityRef`] and [`EntityMut`] which operate in this scope.
#[derive(Clone, Copy)]
pub struct Full;
impl Scope for Full {
fn can_read(&self, component: ComponentId) -> bool { true }
fn can_write(&self, component: ComponentId) -> bool { true }
}
/// [`EntityPtr`] [`Scope`] that provides full access to an entity's components
/// and the [`World`] that the entity is contained in.
///
/// See [`EntityWorldMut`] which operates in this scope.
#[derive(Clone, Copy)]
pub struct Global;
impl Scope for Global {
fn can_read(&self, component: ComponentId) -> bool { true }
fn can_write(&self, component: ComponentId) -> bool { true }
}
/// [`Scope`] that filters an [`EntityPtr`]'s access to its components
/// based on a provided [`Access<ComponentId>`].
///
/// See [`FilteredEntityRef`] and [`FilteredEntityMut`] which operate in this
/// scope.
#[derive(Clone)]
pub struct Partial(pub Access<ComponentId>);
impl Scope for Partial {
fn can_read(&self, component: ComponentId) -> bool {
self.0.has_component_read(component)
}
fn can_write(&self, component: ComponentId) -> bool {
self.0.has_component_write(component)
}
}
/// [`Scope`] that allows an [`EntityPtr`] access to *only* the components
/// which are included in the [`Bundle`] `B`.
///
/// See [`EntityRefOnly`] and [`EntityMutOnly`] which operate in this scope.
#[derive(Clone, Copy)]
pub struct Only<B: Bundle>(PhantomData<B>);
impl<B: Bundle> Scope for Only<B> {
// TODO
}
/// [`Scope`] that allows an [`EntityPtr`] access to all of its components,
/// *except* those included in the [`Bundle`] `B`.
///
/// See [`EntityRefExcept`] and [`EntityMutExcept`] which operate in this
/// scope.
#[derive(Clone, Copy)]
pub struct Except<B: Bundle>(PhantomData<B>);
impl<B: Bundle> Scope for Except<B> {
// TODO
}
mod sealed {
pub trait Capability {}
impl Capability for super::Shared {}
impl Capability for super::Exclusive {}
pub trait Scope {}
impl Scope for super::Full {}
impl Scope for super::Global {}
impl Scope for super::Partial {}
impl<B: Bundle> Scope for super::Only<B> {}
impl<B: Bundle> Scope for super::Except<B> {}
}
```
## Order of PRs
1. Add `EntityPtr` type and turn `EntityRef` and `EntityMut` into type aliases.
2. Change `EntityWorldMut` to hold an `UnsafeEntityCell` instead of `(&mut World, EntityLocation, Entity)`.
3. Change `EntityWorldMut` into a type alias and add `Global` scope.
4. Turn `FilteredEntityRef` and `FilteredEntityMut` into type aliases and add `Partial` scope.
5. Turn `EntityRefExcept` and `EntityMutExcept` into type aliases and add `Except` scope.
6. Add `EntityRefOnly` and `EntityMutOnly` type aliases and `Only` scope.
7. Add `EntityPtr::split` functions to split access over a single entity pointer.
# What if we used references instead?
Instead of modeling access levels with generics on `EntityPtr`, they could be modeled with references to an `EntityView` instead. We can use them directly, no need to
How
We can avoid a lot of cognitive load on the user/complexity budget this way.
Instead of representing scope with a generic, we let the lifetime of the respective `EntityAccess` type constrain the lifetime of any access. This works, even in the presence of `*Ref` clones and copies.
```rust
#[derive(Clone, Copy)]
pub struct EntityView<'w>(UnsafeEntityCell<'w>);
impl<'w> EntityView {
// ... EntityView-specific methods, separated by &self/&mut self as needed
// ... if desired style-wise, they can be in separate impl blocks
}
// Due to lifetime elision rules, the inner 'w lifetime
// will be constrained by the &self lifetime in `Clone`/`Copy`!
#[derive(Clone, Copy)]
pub struct EntityRef<'w>(EntityView<'w>);
impl<'w> Deref for EntityRef<'w> {
type Target = EntityView<'w>
// ...
}
// derefs to EntityRef via &mut -> & coercion
pub type EntityMut<'w>(EntityView<'w>);
impl<'w> Deref for EntityMut<'w> {
type Target = EntityView<'w>
// ...
}
impl<'w> DerefMut for EntityMut<'w>{
// ...
}
```
The Clone/Copy impl split remains even when derefed!
These used to be direct trait aliases to references, but were changed to newtypes to allow for the `QueryData` impl.
Instead, each newtype now derefs to its matching reference type.
```rust
// derefs to EntityRef, mutably derefs to EntityMut
pub struct EntityWorldMut<'w>(EntityView<'w>);
impl<'w> EntityWorldMut<'w> {
//.. EntityWorldMut-specific methods
}
impl<'w> Deref for EntityWorldMut<'w> {
type Target = EntityView<'w>
// ...
}
impl<'w> DerefMut for EntityWorldMut<'w> {
// ...
}
```
Given that immutable access to world can be granted via a `world(&self) -> &World` method, an `EntityWorldRef` is not necessary. (Immutable access with sole focus on an entity would just be `EntityRef`, which is covered by the `Deref` impl)
However, if a `ÈntityWorldRef` is still desired, it could also be added, with `Deref` into `EntityRef`.
```rust
#[derive(Clone, Copy)]
pub struct FilteredEntityView<'w>{
entity: UnsafeEntityCell<'w>,
access: ComponentId
}
// if desired style-wise, they can be in separate impl blocks
impl<'w> FilteredEntityView {
// ... FilteredEntityView-specific methods, separated by &self/&mut self as needed
// fn as_readonly(&self) -> Self;
}
#[derive(Clone, Copy)]
pub struct FilteredEntityRef<'w>(FilteredEntityView<'w>);
impl<'w> Deref for FilteredEntityRef<'w> {
type Target = FilteredEntityView<'w>
// ...
}
pub struct FilteredEntityMut<'w>(FilteredEntityView<'w>);
impl<'w> Deref for FilteredEntityMut<'w> {
type Target = FilteredEntityView<'w>
// ...
}
impl<'w> DerefMut for FilteredEntityMut<'w>{
// ...
}
```
The Filtered and Except variants follow he same schema.
```rust
#[derive(Clone, Copy)]
pub struct EntityViewExcept<'w, B>(UnsafeEntityCell<'w>, PhantomData<B>);
// if desired style-wise, they can be in separate impl blocks
impl<'w> EntityViewExcept {
// ... EntityViewExcept-specific methods, separated by &self/&mut self as needed
}
#[derive(Clone, Copy)]
pub struct EntityRefExcept<'w, B>(EntityViewExcept<'w, B>);
impl<'w> Deref for EntityRefExcept<'w> {
type Target = EntityViewExcept<'w>
// ...
}
pub struct EntityMutExcept<'w, B>(EntityViewExcept<'w, B>);
impl<'w> Deref for EntityMutExcept<'w> {
type Target = EntityViewExcept<'w>
// ...
}
impl<'w> DerefMut for EntityMutExcept<'w>{
// ...
}
```
While all of the above conceptually share functionality, a pair of traits is provided to abstract over it.
While the underlying implementations all use `UnsafeEntityCell`, we don't want to expose a deref/trait impl to it from the various views, since correctness is no longer guaranteed without abstraction.
```rust
pub trait EntityAccess {
// shared methods for all the immutable entity pointers in one place!
// ...
fn reborrow(&mut self) -> Self;
fn id(&self) -> Entity;
fn location(&self) -> EntityLocation
fn archetype(&self) -> &Archetype;
fn contains<T: Component>(&self) -> bool;
fn contains_id(&self, component_id: ComponentId) -> bool;
fn contains_type_id(&self, type_id: TypeId) -> bool;
fn get<T: Component>(&self) -> Option<&T>;
fn get_components<Q: ReadOnlyQueryData>(&self) -> Option<Q::Item<'_>>;
fn into_borrow<T: Component>(self) -> Option<&'w T>;
fn get_ref<T>(&self) -> Option<Ref<'_, T>>;
fn into_ref<T: Component>(self) -> Option<Ref<'w, T>>;
fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks>;
fn get_change_ticks_by_id(
&self,
component_id: ComponentId,
) -> Option<ComponentTicks>;
fn get_by_id<F: DynamicComponentFetch>(
&self,
component_ids: F,
) -> Result<F::Ref<'_>, EntityComponentError>;
fn into_borrow_by_id<F: DynamicComponentFetch>(
self,
component_ids: F,
) -> Result<F::Ref<'w>, EntityComponentError>;
}
// Due to the nature of &/&mut `as_readonly` has ceased to exist!
pub trait EntityAccessMut: EntityAccess {
// shared methods for all the mutable entity pointers in one place!
// ...
fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>>;
fn into_mut<T: Component>(self) -> Option<Mut<'w, T>>;
fn get_mut_by_id<F: DynamicComponentFetch>(
&mut self,
component_ids: F,
) -> Result<F::Mut<'_>, EntityComponentError>;
unsafe fn get_mut_by_id_unchecked<F: DynamicComponentFetch>(
&self,
component_ids: F,
) -> Result<F::Mut<'_>, EntityComponentError>;
fn into_mut_by_id<F: DynamicComponentFetch>(
self,
component_ids: F,
) -> Result<F::Mut<'w>, EntityComponentError>;
}
// There are a lot of implementation here, but the user only has two unified traits to think about!
// Plus, a lot of this ultimately forwards.
impl EntityAccess for EntityWorldMut { /* ... */ }
impl EntityAccess for &EntityView { /* ... */ }
impl EntityAccess for &FilteredEntityView { /* ... */ }
impl EntityAccess for EntityRefExcept { /* ... */ }
impl EntityAccess for &EntityView { /* ... */ }
impl EntityAccess for &FilteredEntityView { /* ... */ }
impl EntityAccess for &EntityViewExcept { /* ... */ }
// This impl just forwards all methods to &T
impl<'a, T> EntityAccess for &'a mut T where &'a T: EntityAccess { /* ... */ }
impl EntityAccessMut for EntityWorldMut { /* ... */ }
impl EntityAccessMut for &mut EntityView { /* ... */ }
impl EntityAccessMut for &mut FilteredEntityView { /* ... */ }
impl EntityAccessMut for &mut EntityViewExcept { /* ... */ }
// TODO: Deref ladders dont work for consuming methods, and `Deref<Target: EntityAccess>` is not a nice bound, impl the trrait for the newtypes as well?
```