Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FilteredEntityRef conversions #11838

Merged
merged 8 commits into from
Feb 14, 2024
216 changes: 216 additions & 0 deletions crates/bevy_ecs/src/world/entity_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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
Expand Down