FilteredEntityRef conversions (#11838)

# Objective

Right now, it's a bit cumbersome to write code that simultaneously deals
with both `FilteredEntityRef`/`EntityRef` or with
`FilteredEntityMut`/`EntityMut`. This PR aims to make it easier by
allowing conversions (both infallible and fallible) between them.

## Solution

- Added infallible conversions from unfiltered into filtered entity refs
- Added fallible conversions from filtered into unfiltered entity refs

---

## Changelog

- Added the following infallible conversions: (`From`)
  - `EntityRef<'a>` → `FilteredEntityRef<'a>`
  - `&'a EntityRef` → `FilteredEntityRef<'a>`
  - `EntityMut<'a>` → `FilteredEntityRef<'a>`
  - `&'a EntityMut` → `FilteredEntityRef<'a>`
  - `EntityWorldMut<'a>` → `FilteredEntityRef<'a>`
  - `&'a EntityWorldMut` → `FilteredEntityRef<'a>`
  - `EntityMut<'a>` → `FilteredEntityMut<'a>`
  - `&'a mut EntityMut` → `FilteredEntityMut<'a>`
  - `EntityWorldMut<'a>` → `FilteredEntityMut<'a>`
  - `&'a mut EntityWorldMut` → `FilteredEntityMut<'a>`
- Added the following _fallible_ conversions: (`TryFrom`)
  - `FilteredEntityRef<'a>` → `EntityRef<'a>`
  - `&'a FilteredEntityRef` → `EntityRef<'a>`
  - `FilteredEntityMut<'a>` → `EntityRef<'a>`
  - `&'a FilteredEntityMut` → `EntityRef<'a>`
  - `FilteredEntityMut<'a>` → `EntityMut<'a>`
  - `&'a mut FilteredEntityMut` → `EntityMut<'a>`
This commit is contained in:
Marco Buono 2024-02-14 09:29:58 -03:00 committed by GitHub
parent ebf81c609f
commit 0354ce4450
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -12,6 +12,7 @@ use crate::{
use bevy_ptr::{OwningPtr, Ptr};
use bevy_utils::tracing::debug;
use std::{any::TypeId, marker::PhantomData};
use thiserror::Error;
use super::{unsafe_world_cell::UnsafeEntityCell, Ref};
@ -189,6 +190,58 @@ impl<'a> From<&'a EntityMut<'_>> for EntityRef<'a> {
}
}
impl<'a> TryFrom<FilteredEntityRef<'a>> for EntityRef<'a> {
type Error = TryFromFilteredError;
fn try_from(value: FilteredEntityRef<'a>) -> Result<Self, Self::Error> {
if !value.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(value.entity) })
}
}
}
impl<'a> TryFrom<&'a FilteredEntityRef<'_>> for EntityRef<'a> {
type Error = TryFromFilteredError;
fn try_from(value: &'a FilteredEntityRef<'_>) -> Result<Self, Self::Error> {
if !value.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(value.entity) })
}
}
}
impl<'a> TryFrom<FilteredEntityMut<'a>> for EntityRef<'a> {
type Error = TryFromFilteredError;
fn try_from(value: FilteredEntityMut<'a>) -> Result<Self, Self::Error> {
if !value.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(value.entity) })
}
}
}
impl<'a> TryFrom<&'a FilteredEntityMut<'_>> for EntityRef<'a> {
type Error = TryFromFilteredError;
fn try_from(value: &'a FilteredEntityMut<'_>) -> Result<Self, Self::Error> {
if !value.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(value.entity) })
}
}
}
/// Provides mutable access to a single entity and all of its components.
///
/// Contrast with [`EntityWorldMut`], which allows adding and removing components,
@ -375,6 +428,36 @@ impl<'a> From<&'a mut EntityWorldMut<'_>> for EntityMut<'a> {
}
}
impl<'a> TryFrom<FilteredEntityMut<'a>> for EntityMut<'a> {
type Error = TryFromFilteredError;
fn try_from(value: FilteredEntityMut<'a>) -> Result<Self, Self::Error> {
if !value.access.has_read_all() {
Err(TryFromFilteredError::MissingReadAllAccess)
} else if !value.access.has_write_all() {
Err(TryFromFilteredError::MissingWriteAllAccess)
} else {
// SAFETY: check above guarantees exclusive access to all components of the entity.
Ok(unsafe { EntityMut::new(value.entity) })
}
}
}
impl<'a> TryFrom<&'a mut FilteredEntityMut<'_>> for EntityMut<'a> {
type Error = TryFromFilteredError;
fn try_from(value: &'a mut FilteredEntityMut<'_>) -> Result<Self, Self::Error> {
if !value.access.has_read_all() {
Err(TryFromFilteredError::MissingReadAllAccess)
} else if !value.access.has_write_all() {
Err(TryFromFilteredError::MissingWriteAllAccess)
} else {
// SAFETY: check above guarantees exclusive access to all components of the entity.
Ok(unsafe { EntityMut::new(value.entity) })
}
}
}
/// A mutable reference to a particular [`Entity`], and the entire world.
/// This is essentially a performance-optimized `(Entity, &mut World)` tuple,
/// which caches the [`EntityLocation`] to reduce duplicate lookups.
@ -1671,6 +1754,78 @@ impl<'a> From<&'a FilteredEntityMut<'_>> for FilteredEntityRef<'a> {
}
}
impl<'a> From<EntityRef<'a>> for FilteredEntityRef<'a> {
fn from(entity: EntityRef<'a>) -> Self {
// SAFETY:
// - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.0, access)
}
}
}
impl<'a> From<&'a EntityRef<'_>> for FilteredEntityRef<'a> {
fn from(entity: &'a EntityRef<'_>) -> Self {
// SAFETY:
// - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.0, access)
}
}
}
impl<'a> From<EntityMut<'a>> for FilteredEntityRef<'a> {
fn from(entity: EntityMut<'a>) -> Self {
// SAFETY:
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.0, access)
}
}
}
impl<'a> From<&'a EntityMut<'_>> for FilteredEntityRef<'a> {
fn from(entity: &'a EntityMut<'_>) -> Self {
// SAFETY:
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityRef`.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.0, access)
}
}
}
impl<'a> From<EntityWorldMut<'a>> for FilteredEntityRef<'a> {
fn from(entity: EntityWorldMut<'a>) -> Self {
// SAFETY:
// - `EntityWorldMut` guarantees exclusive access to the entire world.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.into_unsafe_entity_cell(), access)
}
}
}
impl<'a> From<&'a EntityWorldMut<'_>> for FilteredEntityRef<'a> {
fn from(entity: &'a EntityWorldMut<'_>) -> Self {
// SAFETY:
// - `EntityWorldMut` guarantees exclusive access to the entire world.
unsafe {
let mut access = Access::default();
access.read_all();
FilteredEntityRef::new(entity.as_unsafe_entity_cell_readonly(), access)
}
}
}
/// Provides mutable access to a single entity and some of its components defined by the contained [`Access`].
pub struct FilteredEntityMut<'w> {
entity: UnsafeEntityCell<'w>,
@ -1848,6 +2003,67 @@ impl<'w> FilteredEntityMut<'w> {
}
}
impl<'a> From<EntityMut<'a>> for FilteredEntityMut<'a> {
fn from(entity: EntityMut<'a>) -> Self {
// SAFETY:
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityMut`.
unsafe {
let mut access = Access::default();
access.read_all();
access.write_all();
FilteredEntityMut::new(entity.0, access)
}
}
}
impl<'a> From<&'a mut EntityMut<'_>> for FilteredEntityMut<'a> {
fn from(entity: &'a mut EntityMut<'_>) -> Self {
// SAFETY:
// - `EntityMut` guarantees exclusive access to all components in the new `FilteredEntityMut`.
unsafe {
let mut access = Access::default();
access.read_all();
access.write_all();
FilteredEntityMut::new(entity.0, access)
}
}
}
impl<'a> From<EntityWorldMut<'a>> for FilteredEntityMut<'a> {
fn from(entity: EntityWorldMut<'a>) -> Self {
// SAFETY:
// - `EntityWorldMut` guarantees exclusive access to the entire world.
unsafe {
let mut access = Access::default();
access.read_all();
access.write_all();
FilteredEntityMut::new(entity.into_unsafe_entity_cell(), access)
}
}
}
impl<'a> From<&'a mut EntityWorldMut<'_>> for FilteredEntityMut<'a> {
fn from(entity: &'a mut EntityWorldMut<'_>) -> Self {
// SAFETY:
// - `EntityWorldMut` guarantees exclusive access to the entire world.
unsafe {
let mut access = Access::default();
access.read_all();
access.write_all();
FilteredEntityMut::new(entity.as_unsafe_entity_cell(), access)
}
}
}
#[derive(Error, Debug)]
pub enum TryFromFilteredError {
#[error("Conversion failed, filtered entity ref does not have read access to all components")]
MissingReadAllAccess,
#[error("Conversion failed, filtered entity ref does not have write access to all components")]
MissingWriteAllAccess,
}
/// Inserts a dynamic [`Bundle`] into the entity.
///
/// # Safety