use core::ops::Index;
use crate::{
entity::{AliveEntity, Entity, EntityId, Location},
query::{ImmutableQuery, Query, QueryItem, Read},
view::get_at,
EntityError, NoSuchEntity,
};
use super::{expect_alive, expect_match, BorrowState, ViewValue};
impl<Q, F, B, E> ViewValue<'_, Q, F, B, E>
where
Q: Query,
F: Query,
B: BorrowState,
{
#[inline]
pub fn get_mut(&mut self, entity: impl AliveEntity) -> Option<QueryItem<'_, Q>> {
let loc = entity.locate(self.entity_set);
if loc.arch == u32::MAX {
return self._get_reserved(entity.id(), loc);
}
self.acquire_borrow();
unsafe { self._get(loc) }
}
#[inline]
pub fn try_get_mut(&mut self, entity: impl Entity) -> Result<QueryItem<'_, Q>, EntityError> {
let loc = entity.lookup(self.entity_set).ok_or(NoSuchEntity)?;
if loc.arch == u32::MAX {
return self
._get_reserved(entity.id(), loc)
.ok_or(EntityError::Mismatch);
}
self.acquire_borrow();
unsafe { self._get(loc) }.ok_or(EntityError::Mismatch)
}
#[inline]
#[track_caller]
pub fn expect_mut(&mut self, entity: impl Entity) -> QueryItem<'_, Q> {
let loc = expect_alive(entity.lookup(self.entity_set));
if loc.arch == u32::MAX {
return expect_match(self._get_reserved(entity.id(), loc));
}
self.acquire_borrow();
expect_match(unsafe { self._get(loc) })
}
#[inline]
pub fn map_mut<Fun, R>(&mut self, entity: impl AliveEntity, f: Fun) -> Option<R>
where
Fun: FnOnce(QueryItem<Q>) -> R,
{
let loc = entity.locate(self.entity_set);
if loc.arch == u32::MAX {
return self._get_reserved(entity.id(), loc).map(f);
}
self.with_borrow(loc.arch, || unsafe { self._get(loc) }.map(f))
}
#[inline]
pub fn try_map_mut<Fun, R>(&mut self, entity: impl Entity, f: Fun) -> Result<R, EntityError>
where
Fun: FnOnce(QueryItem<Q>) -> R,
{
let loc = entity
.lookup(self.entity_set)
.ok_or(EntityError::NoSuchEntity)?;
if loc.arch == u32::MAX {
return self
._get_reserved(entity.id(), loc)
.map(f)
.ok_or(EntityError::Mismatch);
}
self.with_borrow(loc.arch, || unsafe { self._get(loc) }.map(f))
.ok_or(EntityError::Mismatch)
}
#[inline]
fn _get_reserved(&self, id: EntityId, loc: Location) -> Option<QueryItem<'_, Q>> {
debug_assert_eq!(loc.arch, u32::MAX);
Query::reserved_entity_item(&self.query, id, loc.idx)
}
#[inline]
unsafe fn _get(&self, loc: Location) -> Option<QueryItem<'_, Q>> {
debug_assert_ne!(loc.arch, u32::MAX);
unsafe {
get_at(
self.query,
self.filter,
self.epochs,
&self.archetypes[loc.arch as usize],
loc,
)
}
}
}
impl<Q, F, B, E> ViewValue<'_, Q, F, B, E>
where
Q: ImmutableQuery,
F: ImmutableQuery,
B: BorrowState,
{
#[inline]
pub fn get(&self, entity: impl AliveEntity) -> Option<QueryItem<'_, Q>> {
let loc = entity.locate(self.entity_set);
if loc.arch == u32::MAX {
return Query::reserved_entity_item(&self.query, entity.id(), loc.idx);
}
self.acquire_borrow();
unsafe { self._get(loc) }
}
#[inline]
pub fn try_get(&self, entity: impl Entity) -> Result<QueryItem<'_, Q>, EntityError> {
let loc = entity.lookup(self.entity_set).ok_or(NoSuchEntity)?;
if loc.arch == u32::MAX {
return Query::reserved_entity_item(&self.query, entity.id(), loc.idx)
.ok_or(EntityError::Mismatch);
}
self.acquire_borrow();
unsafe { self._get(loc) }.ok_or(EntityError::Mismatch)
}
#[inline]
#[track_caller]
pub fn expect(&self, entity: impl Entity) -> QueryItem<'_, Q> {
let loc = expect_alive(entity.lookup(self.entity_set));
if loc.arch == u32::MAX {
return expect_match(Query::reserved_entity_item(
&self.query,
entity.id(),
loc.idx,
));
}
self.acquire_borrow();
expect_match(unsafe { self._get(loc) })
}
#[inline]
pub fn map<Fun, R>(&self, entity: impl AliveEntity, f: Fun) -> Option<R>
where
Fun: FnOnce(QueryItem<Q>) -> R,
{
let loc = entity.locate(self.entity_set);
if loc.arch == u32::MAX {
return Query::reserved_entity_item(&self.query, entity.id(), loc.idx).map(f);
}
self.with_borrow(loc.arch, || unsafe { self._get(loc) }.map(f))
}
#[inline]
pub fn try_map<Fun, R>(&self, entity: impl Entity, f: Fun) -> Result<R, EntityError>
where
Fun: FnOnce(QueryItem<Q>) -> R,
{
let loc = entity
.lookup(self.entity_set)
.ok_or(EntityError::NoSuchEntity)?;
if loc.arch == u32::MAX {
return Query::reserved_entity_item(&self.query, entity.id(), loc.idx)
.map(f)
.ok_or(EntityError::Mismatch);
}
self.with_borrow(loc.arch, || unsafe { self._get(loc) }.map(f))
.ok_or(EntityError::Mismatch)
}
}
impl<E, T, F, B, X> Index<E> for ViewValue<'_, Read<T>, F, B, X>
where
E: Entity,
T: 'static + Sync,
F: ImmutableQuery,
B: BorrowState,
{
type Output = T;
#[inline]
fn index(&self, entity: E) -> &T {
let entity = entity
.entity_loc(self.entity_set)
.expect("Entity is not alive");
self.get(entity)
.expect("Entity does not match view's query and filter")
}
}