use crate::{
archetype::{chunk_idx, Archetype},
entity::{EntitySet, Location},
epoch::EpochCounter,
query::{AsQuery, Fetch, Query, QueryItem},
world::World,
};
pub use self::{
borrow::{
acquire, release, BorrowState, ExclusivelyBorrowed, ExtendableBorrowState,
RuntimeBorrowState, StaticallyBorrowed,
},
iter::ViewIter,
one::{ViewOne, ViewOneState},
};
mod borrow;
mod extend;
mod index;
mod iter;
mod one;
#[derive(Clone)]
#[must_use]
pub struct ViewValue<'a, Q: Query, F: Query, B: BorrowState> {
archetypes: &'a [Archetype],
query: Q,
filter: F,
state: B,
entity_set: &'a EntitySet,
epochs: &'a EpochCounter,
}
impl<'a, Q, F, B> Drop for ViewValue<'a, Q, F, B>
where
Q: Query,
F: Query,
B: BorrowState,
{
#[inline(always)]
fn drop(&mut self) {
self.release_borrow();
}
}
impl<'a, Q, F, B> ViewValue<'a, Q, F, B>
where
Q: Query,
F: Query,
B: BorrowState,
{
#[inline(always)]
fn acquire_borrow(&self) {
self.state.acquire(self.query, self.filter, self.archetypes);
}
#[inline(always)]
fn release_borrow(&self) {
self.state.release(self.query, self.filter, self.archetypes);
}
#[inline(always)]
fn with_borrow<R>(&self, arch_idx: u32, f: impl FnOnce() -> R) -> R {
self.state.with(
self.query,
self.filter,
&self.archetypes[arch_idx as usize],
f,
)
}
#[inline(always)]
fn extract_state(self) -> B {
self.state.release(self.query, self.filter, self.archetypes);
let me = core::mem::ManuallyDrop::new(self);
unsafe { core::ptr::read(&me.state) }
}
}
impl<'a, Q, F, B> ViewValue<'a, Q, F, B>
where
Q: Query,
F: Query,
B: BorrowState,
{
#[inline(always)]
pub fn lock(&mut self) -> ViewValue<'_, Q, F, StaticallyBorrowed> {
self.acquire_borrow();
ViewValue {
archetypes: self.archetypes,
query: self.query,
filter: self.filter,
state: StaticallyBorrowed,
entity_set: self.entity_set,
epochs: self.epochs,
}
}
#[inline(always)]
pub fn unlock(&mut self) {
self.release_borrow()
}
}
pub type ViewCell<'a, Q, F = ()> =
ViewValue<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query, RuntimeBorrowState>;
pub type ViewMut<'a, Q, F = ()> =
ViewValue<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query, ExclusivelyBorrowed>;
pub type View<'a, Q, F = ()> =
ViewValue<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query, StaticallyBorrowed>;
impl<'a, Q, F> ViewValue<'a, Q, F, StaticallyBorrowed>
where
Q: Query,
F: Query,
{
#[inline(always)]
pub unsafe fn new_static(world: &'a World, query: Q, filter: F) -> Self {
ViewValue {
query: query,
filter: filter,
archetypes: world.archetypes(),
state: StaticallyBorrowed,
entity_set: world.entities(),
epochs: world.epoch_counter(),
}
}
}
impl<'a, Q, F> ViewValue<'a, Q, F, ExclusivelyBorrowed>
where
Q: Query,
F: Query,
{
#[inline(always)]
pub fn new(world: &'a mut World, query: Q, filter: F) -> Self {
ViewValue {
archetypes: world.archetypes(),
query,
filter,
state: ExclusivelyBorrowed,
entity_set: world.entities(),
epochs: world.epoch_counter(),
}
}
#[inline(always)]
pub unsafe fn new_unchecked(world: &'a World, query: Q, filter: F) -> Self {
ViewValue {
query: query,
filter: filter,
archetypes: world.archetypes(),
state: ExclusivelyBorrowed,
entity_set: world.entities(),
epochs: world.epoch_counter(),
}
}
}
impl<'a, Q, F> ViewValue<'a, Q, F, RuntimeBorrowState>
where
Q: Query,
F: Query,
{
#[inline(always)]
pub fn new_cell(world: &'a World, query: Q, filter: F) -> Self {
ViewValue {
query: query,
filter: filter,
archetypes: world.archetypes(),
state: RuntimeBorrowState::new(),
entity_set: world.entities(),
epochs: world.epoch_counter(),
}
}
}
#[inline(always)]
#[track_caller]
fn expect_match<T>(value: Option<T>) -> T {
value.expect("Entity does not match view's query and filter")
}
#[inline(always)]
#[track_caller]
fn expect_alive<T>(value: Option<T>) -> T {
value.expect("Entity is not alive")
}
#[inline(always)]
unsafe fn get_at<'a, Q, F>(
query: Q,
filter: F,
epochs: &EpochCounter,
archetype: &'a Archetype,
loc: Location,
) -> Option<QueryItem<'a, Q>>
where
Q: Query,
F: Query,
{
let Location { arch, idx } = loc;
assert!(idx < archetype.len() as u32, "Wrong location");
if !unsafe { query.visit_archetype(archetype) } {
return None;
}
if !unsafe { filter.visit_archetype(archetype) } {
return None;
}
let epoch = epochs.next_if(Q::Query::MUTABLE || F::Query::MUTABLE);
let mut query_fetch = unsafe { query.fetch(arch, archetype, epoch) };
if !unsafe { Fetch::visit_chunk(&mut query_fetch, chunk_idx(idx)) } {
return None;
}
unsafe { Fetch::touch_chunk(&mut query_fetch, chunk_idx(idx)) }
if !unsafe { Fetch::visit_item(&mut query_fetch, idx) } {
return None;
}
let mut filter_fetch = unsafe { filter.fetch(arch, archetype, epoch) };
if !unsafe { Fetch::visit_chunk(&mut filter_fetch, chunk_idx(idx)) } {
return None;
}
unsafe { Fetch::touch_chunk(&mut filter_fetch, chunk_idx(idx)) }
if !unsafe { Fetch::visit_item(&mut filter_fetch, idx) } {
return None;
}
Some(unsafe { Fetch::get_item(&mut query_fetch, idx) })
}