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:
parent
ebf81c609f
commit
0354ce4450
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user