use alloc::vec::Vec;
use core::mem::MaybeUninit;
use crate::{
entity::{Entity, EntityHashMap, EntityHashSet, EntityNotSpawnedError},
error::Result,
world::{
error::EntityMutableFetchError, unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef,
EntityWorldMut,
},
};
pub struct EntityFetcher<'w> {
cell: UnsafeWorldCell<'w>,
}
impl<'w> EntityFetcher<'w> {
pub(crate) unsafe fn new(cell: UnsafeWorldCell<'w>) -> Self {
Self { cell }
}
#[inline]
pub fn get<F: WorldEntityFetch>(
&self,
entities: F,
) -> Result<F::Ref<'_>, EntityNotSpawnedError> {
unsafe { entities.fetch_ref(self.cell) }
}
#[inline]
pub fn get_mut<F: WorldEntityFetch>(
&mut self,
entities: F,
) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {
unsafe { entities.fetch_deferred_mut(self.cell) }
}
}
pub unsafe trait WorldEntityFetch {
type Ref<'w>;
type Mut<'w>;
type DeferredMut<'w>;
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError>;
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError>;
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError>;
}
unsafe impl WorldEntityFetch for Entity {
type Ref<'w> = EntityRef<'w>;
type Mut<'w> = EntityWorldMut<'w>;
type DeferredMut<'w> = EntityMut<'w>;
#[inline]
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError> {
let ecell = cell.get_entity(self)?;
Ok(unsafe { EntityRef::new(ecell) })
}
#[inline]
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError> {
let location = cell.entities().get_spawned(self)?;
let world = unsafe { cell.world_mut() };
Ok(unsafe { EntityWorldMut::new(world, self, Some(location)) })
}
#[inline]
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError> {
let ecell = cell.get_entity(self)?;
Ok(unsafe { EntityMut::new(ecell) })
}
}
unsafe impl<const N: usize> WorldEntityFetch for [Entity; N] {
type Ref<'w> = [EntityRef<'w>; N];
type Mut<'w> = [EntityMut<'w>; N];
type DeferredMut<'w> = [EntityMut<'w>; N];
#[inline]
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError> {
unsafe { <&Self>::fetch_ref(&self, cell) }
}
#[inline]
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError> {
unsafe { <&Self>::fetch_mut(&self, cell) }
}
#[inline]
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError> {
unsafe { <&Self>::fetch_deferred_mut(&self, cell) }
}
}
unsafe impl<const N: usize> WorldEntityFetch for &'_ [Entity; N] {
type Ref<'w> = [EntityRef<'w>; N];
type Mut<'w> = [EntityMut<'w>; N];
type DeferredMut<'w> = [EntityMut<'w>; N];
#[inline]
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError> {
let mut refs = [MaybeUninit::uninit(); N];
for (r, &id) in core::iter::zip(&mut refs, self) {
let ecell = cell.get_entity(id)?;
*r = MaybeUninit::new(unsafe { EntityRef::new(ecell) });
}
let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) });
Ok(refs)
}
#[inline]
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError> {
for i in 0..self.len() {
for j in 0..i {
if self[i] == self[j] {
return Err(EntityMutableFetchError::AliasedMutability(self[i]));
}
}
}
let mut refs = [const { MaybeUninit::uninit() }; N];
for (r, &id) in core::iter::zip(&mut refs, self) {
let ecell = cell.get_entity(id)?;
*r = MaybeUninit::new(unsafe { EntityMut::new(ecell) });
}
let refs = refs.map(|r| unsafe { MaybeUninit::assume_init(r) });
Ok(refs)
}
#[inline]
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError> {
unsafe { self.fetch_mut(cell) }
}
}
unsafe impl WorldEntityFetch for &'_ [Entity] {
type Ref<'w> = Vec<EntityRef<'w>>;
type Mut<'w> = Vec<EntityMut<'w>>;
type DeferredMut<'w> = Vec<EntityMut<'w>>;
#[inline]
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError> {
let mut refs = Vec::with_capacity(self.len());
for &id in self {
let ecell = cell.get_entity(id)?;
refs.push(unsafe { EntityRef::new(ecell) });
}
Ok(refs)
}
#[inline]
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError> {
for i in 0..self.len() {
for j in 0..i {
if self[i] == self[j] {
return Err(EntityMutableFetchError::AliasedMutability(self[i]));
}
}
}
let mut refs = Vec::with_capacity(self.len());
for &id in self {
let ecell = cell.get_entity(id)?;
refs.push(unsafe { EntityMut::new(ecell) });
}
Ok(refs)
}
#[inline]
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError> {
unsafe { self.fetch_mut(cell) }
}
}
unsafe impl WorldEntityFetch for &'_ EntityHashSet {
type Ref<'w> = EntityHashMap<EntityRef<'w>>;
type Mut<'w> = EntityHashMap<EntityMut<'w>>;
type DeferredMut<'w> = EntityHashMap<EntityMut<'w>>;
#[inline]
unsafe fn fetch_ref(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Ref<'_>, EntityNotSpawnedError> {
let mut refs = EntityHashMap::with_capacity(self.len());
for &id in self {
let ecell = cell.get_entity(id)?;
refs.insert(id, unsafe { EntityRef::new(ecell) });
}
Ok(refs)
}
#[inline]
unsafe fn fetch_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::Mut<'_>, EntityMutableFetchError> {
let mut refs = EntityHashMap::with_capacity(self.len());
for &id in self {
let ecell = cell.get_entity(id)?;
refs.insert(id, unsafe { EntityMut::new(ecell) });
}
Ok(refs)
}
#[inline]
unsafe fn fetch_deferred_mut(
self,
cell: UnsafeWorldCell<'_>,
) -> Result<Self::DeferredMut<'_>, EntityMutableFetchError> {
unsafe { self.fetch_mut(cell) }
}
}