#[cfg(feature = "std")]
use core::any::Any;
use core::any::TypeId;
use core::marker::PhantomData;
use core::ptr::NonNull;
use core::slice::Iter as SliceIter;
#[cfg(feature = "std")]
use std::sync::{Arc, RwLock};
use crate::alloc::boxed::Box;
#[cfg(feature = "std")]
use hashbrown::hash_map;
use crate::archetype::Archetype;
use crate::entities::EntityMeta;
#[cfg(feature = "std")]
use crate::TypeIdMap;
use crate::{Component, Entity, World};
pub trait Query {
type Item<'a>;
#[doc(hidden)]
type Fetch: Fetch;
#[doc(hidden)]
unsafe fn get<'a>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'a>;
}
#[allow(clippy::missing_safety_doc)]
pub unsafe trait QueryShared {}
#[allow(clippy::missing_safety_doc)]
pub unsafe trait Fetch: Clone + Sized + 'static {
type State: Copy + Send + Sync;
fn dangling() -> Self;
fn access(archetype: &Archetype) -> Option<Access>;
fn borrow(archetype: &Archetype, state: Self::State);
fn prepare(archetype: &Archetype) -> Option<Self::State>;
fn execute(archetype: &Archetype, state: Self::State) -> Self;
fn release(archetype: &Archetype, state: Self::State);
fn for_each_borrow(f: impl FnMut(TypeId, bool));
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Access {
Iterate,
Read,
Write,
}
impl Query for Entity {
type Item<'q> = Entity;
type Fetch = FetchEntity;
unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
let id = fetch.0.as_ptr().add(n).read();
Entity {
id,
generation: meta.get_unchecked(id as usize).generation,
}
}
}
unsafe impl QueryShared for Entity {}
#[doc(hidden)]
#[derive(Clone)]
pub struct FetchEntity(NonNull<u32>);
unsafe impl Fetch for FetchEntity {
type State = ();
fn dangling() -> Self {
Self(NonNull::dangling())
}
fn access(_: &Archetype) -> Option<Access> {
Some(Access::Iterate)
}
fn borrow(_: &Archetype, (): Self::State) {}
fn prepare(_: &Archetype) -> Option<Self::State> {
Some(())
}
fn execute(archetype: &Archetype, (): Self::State) -> Self {
Self(archetype.entities())
}
fn release(_: &Archetype, (): Self::State) {}
fn for_each_borrow(_: impl FnMut(TypeId, bool)) {}
}
impl<T: Component> Query for &'_ T {
type Item<'q> = &'q T;
type Fetch = FetchRead<T>;
unsafe fn get<'q>(_: &[EntityMeta], fetch: &FetchRead<T>, n: usize) -> &'q T {
&*fetch.0.as_ptr().add(n)
}
}
unsafe impl<T> QueryShared for &'_ T {}
#[doc(hidden)]
pub struct FetchRead<T>(NonNull<T>);
unsafe impl<T: Component> Fetch for FetchRead<T> {
type State = usize;
fn dangling() -> Self {
Self(NonNull::dangling())
}
fn access(archetype: &Archetype) -> Option<Access> {
if archetype.has::<T>() {
Some(Access::Read)
} else {
None
}
}
fn borrow(archetype: &Archetype, state: Self::State) {
archetype.borrow::<T>(state);
}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
archetype.get_state::<T>()
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
unsafe { Self(archetype.get_base(state)) }
}
fn release(archetype: &Archetype, state: Self::State) {
archetype.release::<T>(state);
}
fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
f(TypeId::of::<T>(), false);
}
}
impl<T> Clone for FetchRead<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<T: Component> Query for &'_ mut T {
type Item<'q> = &'q mut T;
type Fetch = FetchWrite<T>;
unsafe fn get<'q>(_: &[EntityMeta], fetch: &FetchWrite<T>, n: usize) -> &'q mut T {
&mut *fetch.0.as_ptr().add(n)
}
}
#[doc(hidden)]
pub struct FetchWrite<T>(NonNull<T>);
unsafe impl<T: Component> Fetch for FetchWrite<T> {
type State = usize;
fn dangling() -> Self {
Self(NonNull::dangling())
}
fn access(archetype: &Archetype) -> Option<Access> {
if archetype.has::<T>() {
Some(Access::Write)
} else {
None
}
}
fn borrow(archetype: &Archetype, state: Self::State) {
archetype.borrow_mut::<T>(state);
}
#[allow(clippy::needless_question_mark)]
fn prepare(archetype: &Archetype) -> Option<Self::State> {
Some(archetype.get_state::<T>()?)
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
unsafe { Self(archetype.get_base::<T>(state)) }
}
fn release(archetype: &Archetype, state: Self::State) {
archetype.release_mut::<T>(state);
}
fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
f(TypeId::of::<T>(), true);
}
}
impl<T> Clone for FetchWrite<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<T: Query> Query for Option<T> {
type Item<'q> = Option<T::Item<'q>>;
type Fetch = TryFetch<T::Fetch>;
unsafe fn get<'q>(
meta: &[EntityMeta],
fetch: &TryFetch<T::Fetch>,
n: usize,
) -> Option<T::Item<'q>> {
Some(T::get(meta, fetch.0.as_ref()?, n))
}
}
unsafe impl<T: QueryShared> QueryShared for Option<T> {}
#[doc(hidden)]
#[derive(Clone)]
pub struct TryFetch<T>(Option<T>);
unsafe impl<T: Fetch> Fetch for TryFetch<T> {
type State = Option<T::State>;
fn dangling() -> Self {
Self(None)
}
fn access(archetype: &Archetype) -> Option<Access> {
Some(T::access(archetype).unwrap_or(Access::Iterate))
}
fn borrow(archetype: &Archetype, state: Self::State) {
if let Some(state) = state {
T::borrow(archetype, state);
}
}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
Some(T::prepare(archetype))
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
Self(state.map(|state| T::execute(archetype, state)))
}
fn release(archetype: &Archetype, state: Self::State) {
if let Some(state) = state {
T::release(archetype, state);
}
}
fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
T::for_each_borrow(f);
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Or<L, R> {
Left(L),
Right(R),
Both(L, R),
}
impl<L, R> Or<L, R> {
pub fn new(l: Option<L>, r: Option<R>) -> Option<Self> {
match (l, r) {
(None, None) => None,
(Some(l), None) => Some(Or::Left(l)),
(None, Some(r)) => Some(Or::Right(r)),
(Some(l), Some(r)) => Some(Or::Both(l, r)),
}
}
pub fn split(self) -> (Option<L>, Option<R>) {
match self {
Or::Left(l) => (Some(l), None),
Or::Right(r) => (None, Some(r)),
Or::Both(l, r) => (Some(l), Some(r)),
}
}
pub fn left(self) -> Option<L> {
match self {
Or::Left(l) => Some(l),
Or::Both(l, _) => Some(l),
_ => None,
}
}
pub fn right(self) -> Option<R> {
match self {
Or::Right(r) => Some(r),
Or::Both(_, r) => Some(r),
_ => None,
}
}
pub fn map<L1, R1, F, G>(self, f: F, g: G) -> Or<L1, R1>
where
F: FnOnce(L) -> L1,
G: FnOnce(R) -> R1,
{
match self {
Or::Left(l) => Or::Left(f(l)),
Or::Right(r) => Or::Right(g(r)),
Or::Both(l, r) => Or::Both(f(l), g(r)),
}
}
pub fn as_ref(&self) -> Or<&L, &R> {
match *self {
Or::Left(ref l) => Or::Left(l),
Or::Right(ref r) => Or::Right(r),
Or::Both(ref l, ref r) => Or::Both(l, r),
}
}
pub fn as_mut(&mut self) -> Or<&mut L, &mut R> {
match *self {
Or::Left(ref mut l) => Or::Left(l),
Or::Right(ref mut r) => Or::Right(r),
Or::Both(ref mut l, ref mut r) => Or::Both(l, r),
}
}
}
impl<L, R> Or<&'_ L, &'_ R>
where
L: Clone,
R: Clone,
{
pub fn cloned(self) -> Or<L, R> {
self.map(Clone::clone, Clone::clone)
}
}
impl<L: Query, R: Query> Query for Or<L, R> {
type Item<'q> = Or<L::Item<'q>, R::Item<'q>>;
type Fetch = FetchOr<L::Fetch, R::Fetch>;
unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
fetch
.0
.as_ref()
.map(|l| L::get(meta, l, n), |r| R::get(meta, r, n))
}
}
unsafe impl<L: QueryShared, R: QueryShared> QueryShared for Or<L, R> {}
#[doc(hidden)]
#[derive(Clone)]
pub struct FetchOr<L, R>(Or<L, R>);
unsafe impl<L: Fetch, R: Fetch> Fetch for FetchOr<L, R> {
type State = Or<L::State, R::State>;
fn dangling() -> Self {
Self(Or::Left(L::dangling()))
}
fn access(archetype: &Archetype) -> Option<Access> {
L::access(archetype).max(R::access(archetype))
}
fn borrow(archetype: &Archetype, state: Self::State) {
state.map(|l| L::borrow(archetype, l), |r| R::borrow(archetype, r));
}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
Or::new(L::prepare(archetype), R::prepare(archetype))
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
Self(state.map(|l| L::execute(archetype, l), |r| R::execute(archetype, r)))
}
fn release(archetype: &Archetype, state: Self::State) {
state.map(|l| L::release(archetype, l), |r| R::release(archetype, r));
}
fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
L::for_each_borrow(&mut f);
R::for_each_borrow(&mut f);
}
}
pub struct Without<Q, R>(PhantomData<(Q, fn(R))>);
impl<Q: Query, R: Query> Query for Without<Q, R> {
type Item<'q> = Q::Item<'q>;
type Fetch = FetchWithout<Q::Fetch, R::Fetch>;
unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
Q::get(meta, &fetch.0, n)
}
}
unsafe impl<Q: QueryShared, R> QueryShared for Without<Q, R> {}
#[doc(hidden)]
pub struct FetchWithout<F, G>(F, PhantomData<fn(G)>);
unsafe impl<F: Fetch, G: Fetch> Fetch for FetchWithout<F, G> {
type State = F::State;
fn dangling() -> Self {
Self(F::dangling(), PhantomData)
}
fn access(archetype: &Archetype) -> Option<Access> {
if G::access(archetype).is_some() {
None
} else {
F::access(archetype)
}
}
fn borrow(archetype: &Archetype, state: Self::State) {
F::borrow(archetype, state)
}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
if G::access(archetype).is_some() {
return None;
}
F::prepare(archetype)
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
Self(F::execute(archetype, state), PhantomData)
}
fn release(archetype: &Archetype, state: Self::State) {
F::release(archetype, state)
}
fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
F::for_each_borrow(f);
}
}
impl<F: Clone, G> Clone for FetchWithout<F, G> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
pub struct With<Q, R>(PhantomData<(Q, fn(R))>);
impl<Q: Query, R: Query> Query for With<Q, R> {
type Item<'q> = Q::Item<'q>;
type Fetch = FetchWith<Q::Fetch, R::Fetch>;
unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
Q::get(meta, &fetch.0, n)
}
}
unsafe impl<Q: QueryShared, R> QueryShared for With<Q, R> {}
#[doc(hidden)]
pub struct FetchWith<F, G>(F, PhantomData<fn(G)>);
unsafe impl<F: Fetch, G: Fetch> Fetch for FetchWith<F, G> {
type State = F::State;
fn dangling() -> Self {
Self(F::dangling(), PhantomData)
}
fn access(archetype: &Archetype) -> Option<Access> {
if G::access(archetype).is_some() {
F::access(archetype)
} else {
None
}
}
fn borrow(archetype: &Archetype, state: Self::State) {
F::borrow(archetype, state)
}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
G::access(archetype)?;
F::prepare(archetype)
}
fn execute(archetype: &Archetype, state: Self::State) -> Self {
Self(F::execute(archetype, state), PhantomData)
}
fn release(archetype: &Archetype, state: Self::State) {
F::release(archetype, state)
}
fn for_each_borrow(f: impl FnMut(TypeId, bool)) {
F::for_each_borrow(f);
}
}
impl<F: Clone, G> Clone for FetchWith<F, G> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone(), PhantomData)
}
}
pub struct Satisfies<Q>(PhantomData<Q>);
impl<Q: Query> Query for Satisfies<Q> {
type Item<'q> = bool;
type Fetch = FetchSatisfies<Q::Fetch>;
unsafe fn get<'q>(_: &[EntityMeta], fetch: &Self::Fetch, _: usize) -> Self::Item<'q> {
fetch.0
}
}
unsafe impl<Q> QueryShared for Satisfies<Q> {}
#[doc(hidden)]
pub struct FetchSatisfies<F>(bool, PhantomData<F>);
unsafe impl<F: Fetch> Fetch for FetchSatisfies<F> {
type State = bool;
fn dangling() -> Self {
Self(false, PhantomData)
}
fn access(_archetype: &Archetype) -> Option<Access> {
Some(Access::Iterate)
}
fn borrow(_archetype: &Archetype, _state: Self::State) {}
fn prepare(archetype: &Archetype) -> Option<Self::State> {
Some(F::prepare(archetype).is_some())
}
fn execute(_archetype: &Archetype, state: Self::State) -> Self {
Self(state, PhantomData)
}
fn release(_archetype: &Archetype, _state: Self::State) {}
fn for_each_borrow(_: impl FnMut(TypeId, bool)) {}
}
impl<T> Clone for FetchSatisfies<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0, PhantomData)
}
}
pub struct QueryBorrow<'w, Q: Query> {
world: &'w World,
cache: Option<CachedQuery<Q::Fetch>>,
}
impl<'w, Q: Query> QueryBorrow<'w, Q> {
pub(crate) fn new(world: &'w World) -> Self {
Self { world, cache: None }
}
pub fn iter(&mut self) -> QueryIter<'_, Q> {
let cache = self.borrow().clone();
unsafe { QueryIter::new(self.world, cache) }
}
pub fn view(&mut self) -> View<'_, Q> {
let cache = self.borrow().clone();
unsafe {
View::new(
self.world.entities_meta(),
self.world.archetypes_inner(),
cache,
)
}
}
pub fn iter_batched(&mut self, batch_size: u32) -> BatchedIter<'_, Q> {
let cache = self.borrow().clone();
unsafe {
BatchedIter::new(
self.world.entities_meta(),
self.world.archetypes_inner(),
batch_size,
cache,
)
}
}
fn borrow(&mut self) -> &CachedQuery<Q::Fetch> {
self.cache.get_or_insert_with(|| {
let cache = CachedQuery::get(self.world);
cache.borrow(self.world.archetypes_inner());
cache
})
}
pub fn with<R: Query>(self) -> QueryBorrow<'w, With<Q, R>> {
self.transform()
}
pub fn without<R: Query>(self) -> QueryBorrow<'w, Without<Q, R>> {
self.transform()
}
fn transform<R: Query>(self) -> QueryBorrow<'w, R> {
QueryBorrow {
world: self.world,
cache: None,
}
}
}
unsafe impl<Q: Query> Send for QueryBorrow<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for QueryBorrow<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<Q: Query> Drop for QueryBorrow<'_, Q> {
fn drop(&mut self) {
if let Some(cache) = &self.cache {
cache.release_borrow(self.world.archetypes_inner());
}
}
}
impl<'q, Q: Query> IntoIterator for &'q mut QueryBorrow<'_, Q> {
type Item = Q::Item<'q>;
type IntoIter = QueryIter<'q, Q>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub struct QueryIter<'q, Q: Query> {
world: &'q World,
archetypes: ArchetypeIter<Q>,
iter: ChunkIter<Q>,
}
impl<'q, Q: Query> QueryIter<'q, Q> {
unsafe fn new(world: &'q World, cache: CachedQuery<Q::Fetch>) -> Self {
Self {
world,
archetypes: ArchetypeIter::new(world, cache),
iter: ChunkIter::empty(),
}
}
}
unsafe impl<Q: Query> Send for QueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for QueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<'q, Q: Query> Iterator for QueryIter<'q, Q> {
type Item = Q::Item<'q>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
match unsafe { self.iter.next(self.world.entities_meta()) } {
None => {
unsafe {
self.iter = self.archetypes.next(self.world)?;
}
continue;
}
Some(components) => {
return Some(components);
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
(n, Some(n))
}
}
impl<Q: Query> ExactSizeIterator for QueryIter<'_, Q> {
fn len(&self) -> usize {
self.archetypes.entity_len(self.world) + self.iter.remaining()
}
}
pub struct QueryMut<'q, Q: Query> {
world: &'q mut World,
_marker: PhantomData<fn() -> Q>,
}
impl<'q, Q: Query> QueryMut<'q, Q> {
pub(crate) fn new(world: &'q mut World) -> Self {
assert_borrow::<Q>();
Self {
world,
_marker: PhantomData,
}
}
pub fn view(&mut self) -> View<'_, Q> {
let cache = CachedQuery::get(self.world);
unsafe {
View::new(
self.world.entities_meta(),
self.world.archetypes_inner(),
cache,
)
}
}
pub fn with<R: Query>(self) -> QueryMut<'q, With<Q, R>> {
self.transform()
}
pub fn without<R: Query>(self) -> QueryMut<'q, Without<Q, R>> {
self.transform()
}
fn transform<R: Query>(self) -> QueryMut<'q, R> {
QueryMut {
world: self.world,
_marker: PhantomData,
}
}
pub fn into_iter_batched(self, batch_size: u32) -> BatchedIter<'q, Q> {
let cache = CachedQuery::get(self.world);
unsafe {
BatchedIter::new(
self.world.entities_meta(),
self.world.archetypes_inner(),
batch_size,
cache,
)
}
}
}
impl<'q, Q: Query> IntoIterator for QueryMut<'q, Q> {
type Item = <QueryIter<'q, Q> as Iterator>::Item;
type IntoIter = QueryIter<'q, Q>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let cache = CachedQuery::get(self.world);
unsafe { QueryIter::new(self.world, cache) }
}
}
pub(crate) fn assert_borrow<Q: Query>() {
let mut i = 0;
Q::Fetch::for_each_borrow(|a, unique| {
if unique {
let mut j = 0;
Q::Fetch::for_each_borrow(|b, _| {
if i != j {
core::assert!(a != b, "query violates a unique borrow");
}
j += 1;
})
}
i += 1;
});
}
struct ChunkIter<Q: Query> {
fetch: Q::Fetch,
position: usize,
len: usize,
}
impl<Q: Query> ChunkIter<Q> {
fn new(archetype: &Archetype, fetch: Q::Fetch) -> Self {
Self {
fetch,
position: 0,
len: archetype.len() as usize,
}
}
fn empty() -> Self {
Self {
fetch: Q::Fetch::dangling(),
position: 0,
len: 0,
}
}
#[inline]
unsafe fn next<'a>(&mut self, meta: &[EntityMeta]) -> Option<Q::Item<'a>> {
if self.position == self.len {
return None;
}
let item = Q::get(meta, &self.fetch, self.position);
self.position += 1;
Some(item)
}
fn remaining(&self) -> usize {
self.len - self.position
}
}
pub struct BatchedIter<'q, Q: Query> {
_marker: PhantomData<&'q Q>,
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
index_iter: core::ops::Range<usize>,
batch_size: u32,
cache: CachedQuery<Q::Fetch>,
batch: u32,
}
impl<'q, Q: Query> BatchedIter<'q, Q> {
unsafe fn new(
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
batch_size: u32,
cache: CachedQuery<Q::Fetch>,
) -> Self {
Self {
_marker: PhantomData,
meta,
archetypes,
index_iter: (0..cache.archetype_count(archetypes)),
batch_size,
cache,
batch: 0,
}
}
}
unsafe impl<Q: Query> Send for BatchedIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for BatchedIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<'q, Q: Query> Iterator for BatchedIter<'q, Q> {
type Item = Batch<'q, Q>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut indices = self.index_iter.clone();
let index = indices.next()?;
let Some((archetype, state)) =
(unsafe { self.cache.get_state(self.archetypes, index) })
else {
self.index_iter = indices;
continue;
};
let offset = self.batch_size * self.batch;
if offset >= archetype.len() {
self.index_iter = indices;
self.batch = 0;
continue;
}
let fetch = Q::Fetch::execute(archetype, state);
self.batch += 1;
let mut state = ChunkIter::new(archetype, fetch);
state.position = offset as usize;
state.len = (offset + self.batch_size.min(archetype.len() - offset)) as usize;
return Some(Batch {
meta: self.meta,
state,
});
}
}
}
pub struct Batch<'q, Q: Query> {
meta: &'q [EntityMeta],
state: ChunkIter<Q>,
}
impl<'q, Q: Query> Iterator for Batch<'q, Q> {
type Item = Q::Item<'q>;
fn next(&mut self) -> Option<Self::Item> {
unsafe { self.state.next(self.meta) }
}
}
unsafe impl<Q: Query> Send for Batch<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for Batch<'_, Q> where for<'a> Q::Item<'a>: Send {}
macro_rules! tuple_impl {
($($name: ident),*) => {
unsafe impl<$($name: Fetch),*> Fetch for ($($name,)*) {
type State = ($($name::State,)*);
#[allow(clippy::unused_unit)]
fn dangling() -> Self {
($($name::dangling(),)*)
}
#[allow(unused_variables, unused_mut)]
fn access(archetype: &Archetype) -> Option<Access> {
let mut access = Access::Iterate;
$(
access = access.max($name::access(archetype)?);
)*
Some(access)
}
#[allow(unused_variables, non_snake_case, clippy::unused_unit)]
fn borrow(archetype: &Archetype, state: Self::State) {
let ($($name,)*) = state;
$($name::borrow(archetype, $name);)*
}
#[allow(unused_variables)]
#[cold]
fn prepare(archetype: &Archetype) -> Option<Self::State> {
Some(($($name::prepare(archetype)?,)*))
}
#[allow(unused_variables, non_snake_case, clippy::unused_unit)]
#[inline(always)]
fn execute(archetype: &Archetype, state: Self::State) -> Self {
let ($($name,)*) = state;
($($name::execute(archetype, $name),)*)
}
#[allow(unused_variables, non_snake_case, clippy::unused_unit)]
fn release(archetype: &Archetype, state: Self::State) {
let ($($name,)*) = state;
$($name::release(archetype, $name);)*
}
#[allow(unused_variables, unused_mut, clippy::unused_unit)]
fn for_each_borrow(mut f: impl FnMut(TypeId, bool)) {
$($name::for_each_borrow(&mut f);)*
}
}
impl<$($name: Query),*> Query for ($($name,)*) {
type Item<'q> = ($($name::Item<'q>,)*);
type Fetch = ($($name::Fetch,)*);
#[allow(unused_variables, clippy::unused_unit)]
unsafe fn get<'q>(meta: &[EntityMeta], fetch: &Self::Fetch, n: usize) -> Self::Item<'q> {
#[allow(non_snake_case)]
let ($(ref $name,)*) = *fetch;
($($name::get(meta, $name, n),)*)
}
}
unsafe impl<$($name: QueryShared),*> QueryShared for ($($name,)*) {}
};
}
smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
pub struct PreparedQuery<Q: Query> {
memo: (u64, u32),
state: Box<[(usize, <Q::Fetch as Fetch>::State)]>,
fetch: Box<[Option<Q::Fetch>]>,
}
impl<Q: Query> Default for PreparedQuery<Q> {
fn default() -> Self {
Self::new()
}
}
impl<Q: Query> PreparedQuery<Q> {
pub fn new() -> Self {
Self {
memo: (0, 0),
state: Default::default(),
fetch: Default::default(),
}
}
#[cold]
fn prepare(world: &World) -> Self {
let memo = world.memo();
let state = world
.archetypes()
.enumerate()
.filter_map(|(idx, x)| Q::Fetch::prepare(x).map(|state| (idx, state)))
.collect();
let fetch = world.archetypes().map(|_| None).collect();
Self { memo, state, fetch }
}
pub fn query<'q>(&'q mut self, world: &'q World) -> PreparedQueryBorrow<'q, Q> {
if self.memo != world.memo() {
*self = Self::prepare(world);
}
let meta = world.entities_meta();
let archetypes = world.archetypes_inner();
PreparedQueryBorrow::new(meta, archetypes, &self.state, &mut self.fetch)
}
pub fn query_mut<'q>(&'q mut self, world: &'q mut World) -> PreparedQueryIter<'q, Q> {
assert_borrow::<Q>();
if self.memo != world.memo() {
*self = Self::prepare(world);
}
let meta = world.entities_meta();
let archetypes = world.archetypes_inner();
unsafe { PreparedQueryIter::new(meta, archetypes, self.state.iter()) }
}
pub fn view_mut<'q>(&'q mut self, world: &'q mut World) -> PreparedView<'q, Q> {
assert_borrow::<Q>();
if self.memo != world.memo() {
*self = Self::prepare(world);
}
let meta = world.entities_meta();
let archetypes = world.archetypes_inner();
unsafe { PreparedView::new(meta, archetypes, self.state.iter(), &mut self.fetch) }
}
}
pub struct PreparedQueryBorrow<'q, Q: Query> {
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
state: &'q [(usize, <Q::Fetch as Fetch>::State)],
fetch: &'q mut [Option<Q::Fetch>],
}
impl<'q, Q: Query> PreparedQueryBorrow<'q, Q> {
fn new(
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
state: &'q [(usize, <Q::Fetch as Fetch>::State)],
fetch: &'q mut [Option<Q::Fetch>],
) -> Self {
for (idx, state) in state {
if archetypes[*idx].is_empty() {
continue;
}
Q::Fetch::borrow(&archetypes[*idx], *state);
}
Self {
meta,
archetypes,
state,
fetch,
}
}
pub fn iter(&mut self) -> PreparedQueryIter<'_, Q> {
unsafe { PreparedQueryIter::new(self.meta, self.archetypes, self.state.iter()) }
}
pub fn view(&mut self) -> PreparedView<'_, Q> {
unsafe { PreparedView::new(self.meta, self.archetypes, self.state.iter(), self.fetch) }
}
}
impl<Q: Query> Drop for PreparedQueryBorrow<'_, Q> {
fn drop(&mut self) {
for (idx, state) in self.state {
if self.archetypes[*idx].is_empty() {
continue;
}
Q::Fetch::release(&self.archetypes[*idx], *state);
}
}
}
pub struct PreparedQueryIter<'q, Q: Query> {
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
iter: ChunkIter<Q>,
}
impl<'q, Q: Query> PreparedQueryIter<'q, Q> {
unsafe fn new(
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
) -> Self {
Self {
meta,
archetypes,
state,
iter: ChunkIter::empty(),
}
}
}
unsafe impl<Q: Query> Send for PreparedQueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for PreparedQueryIter<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<'q, Q: Query> Iterator for PreparedQueryIter<'q, Q> {
type Item = Q::Item<'q>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
match unsafe { self.iter.next(self.meta) } {
None => {
let (idx, state) = self.state.next()?;
let archetype = &self.archetypes[*idx];
self.iter = ChunkIter::new(archetype, Q::Fetch::execute(archetype, *state));
continue;
}
Some(components) => {
return Some(components);
}
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
(n, Some(n))
}
}
impl<Q: Query> ExactSizeIterator for PreparedQueryIter<'_, Q> {
fn len(&self) -> usize {
self.state
.clone()
.map(|(idx, _)| self.archetypes[*idx].len() as usize)
.sum::<usize>()
+ self.iter.remaining()
}
}
pub struct View<'q, Q: Query> {
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
fetch: Box<[Option<Q::Fetch>]>,
}
unsafe impl<Q: Query> Send for View<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for View<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<'q, Q: Query> View<'q, Q> {
pub(crate) unsafe fn new(
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
cache: CachedQuery<Q::Fetch>,
) -> Self {
Self {
meta,
archetypes,
fetch: cache.fetch_all(archetypes),
}
}
pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
where
Q: QueryShared,
{
let meta = self.meta.get(entity.id as usize)?;
if meta.generation != entity.generation {
return None;
}
self.fetch[meta.location.archetype as usize]
.as_ref()
.map(|fetch| unsafe { Q::get(self.meta, fetch, meta.location.index as usize) })
}
pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
unsafe { self.get_unchecked(entity) }
}
pub fn contains(&self, entity: Entity) -> bool {
let Some(meta) = self.meta.get(entity.id as usize) else {
return false;
};
if meta.generation != entity.generation {
return false;
}
self.fetch[meta.location.archetype as usize].is_some()
}
pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
let meta = self.meta.get(entity.id as usize)?;
if meta.generation != entity.generation {
return None;
}
self.fetch[meta.location.archetype as usize]
.as_ref()
.map(|fetch| Q::get(self.meta, fetch, meta.location.index as usize))
}
pub fn get_disjoint_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
assert_distinct(&entities);
let mut items = [(); N].map(|()| None);
for (item, entity) in items.iter_mut().zip(entities) {
unsafe {
*item = self.get_unchecked(entity);
}
}
items
}
#[doc(hidden)]
#[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
pub fn get_many_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
self.get_disjoint_mut(entities)
}
pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
ViewIter {
meta: self.meta,
archetypes: self.archetypes.iter(),
fetches: self.fetch.iter(),
iter: ChunkIter::empty(),
}
}
}
impl<'a, Q: Query> IntoIterator for &'a mut View<'_, Q> {
type IntoIter = ViewIter<'a, Q>;
type Item = Q::Item<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct ViewIter<'a, Q: Query> {
meta: &'a [EntityMeta],
archetypes: SliceIter<'a, Archetype>,
fetches: SliceIter<'a, Option<Q::Fetch>>,
iter: ChunkIter<Q>,
}
impl<'a, Q: Query> Iterator for ViewIter<'a, Q> {
type Item = Q::Item<'a>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
loop {
match unsafe { self.iter.next(self.meta) } {
None => {
let archetype = self.archetypes.next()?;
let fetch = self.fetches.next()?;
self.iter = fetch
.clone()
.map_or(ChunkIter::empty(), |fetch| ChunkIter::new(archetype, fetch));
continue;
}
Some(components) => {
return Some(components);
}
}
}
}
}
pub struct PreparedView<'q, Q: Query> {
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
fetch: &'q mut [Option<Q::Fetch>],
}
unsafe impl<Q: Query> Send for PreparedView<'_, Q> where for<'a> Q::Item<'a>: Send {}
unsafe impl<Q: Query> Sync for PreparedView<'_, Q> where for<'a> Q::Item<'a>: Send {}
impl<'q, Q: Query> PreparedView<'q, Q> {
unsafe fn new(
meta: &'q [EntityMeta],
archetypes: &'q [Archetype],
state: SliceIter<'q, (usize, <Q::Fetch as Fetch>::State)>,
fetch: &'q mut [Option<Q::Fetch>],
) -> Self {
fetch.iter_mut().for_each(|fetch| *fetch = None);
for (idx, state) in state {
let archetype = &archetypes[*idx];
fetch[*idx] = Some(Q::Fetch::execute(archetype, *state));
}
Self {
meta,
archetypes,
fetch,
}
}
pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
where
Q: QueryShared,
{
let meta = self.meta.get(entity.id as usize)?;
if meta.generation != entity.generation {
return None;
}
self.fetch[meta.location.archetype as usize]
.as_ref()
.map(|fetch| unsafe { Q::get(self.meta, fetch, meta.location.index as usize) })
}
pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
unsafe { self.get_unchecked(entity) }
}
pub fn contains(&self, entity: Entity) -> bool {
let Some(meta) = self.meta.get(entity.id as usize) else {
return false;
};
if meta.generation != entity.generation {
return false;
}
self.fetch[meta.location.archetype as usize].is_some()
}
pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
let meta = self.meta.get(entity.id as usize)?;
if meta.generation != entity.generation {
return None;
}
self.fetch[meta.location.archetype as usize]
.as_ref()
.map(|fetch| Q::get(self.meta, fetch, meta.location.index as usize))
}
pub fn get_disjoint_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
assert_distinct(&entities);
let mut items = [(); N].map(|()| None);
for (item, entity) in items.iter_mut().zip(entities) {
unsafe {
*item = self.get_unchecked(entity);
}
}
items
}
#[doc(hidden)]
#[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
pub fn get_many_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
self.get_disjoint_mut(entities)
}
pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
ViewIter {
meta: self.meta,
archetypes: self.archetypes.iter(),
fetches: self.fetch.iter(),
iter: ChunkIter::empty(),
}
}
}
impl<'a, Q: Query> IntoIterator for &'a mut PreparedView<'_, Q> {
type IntoIter = ViewIter<'a, Q>;
type Item = Q::Item<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub struct ViewBorrow<'w, Q: Query> {
view: View<'w, Q>,
cache: CachedQuery<Q::Fetch>,
}
impl<'w, Q: Query> ViewBorrow<'w, Q> {
pub(crate) fn new(world: &'w World) -> Self {
let cache = CachedQuery::get(world);
cache.borrow(world.archetypes_inner());
let view = unsafe {
View::<Q>::new(
world.entities_meta(),
world.archetypes_inner(),
cache.clone(),
)
};
Self { view, cache }
}
pub fn get(&self, entity: Entity) -> Option<Q::Item<'_>>
where
Q: QueryShared,
{
self.view.get(entity)
}
pub fn get_mut(&mut self, entity: Entity) -> Option<Q::Item<'_>> {
self.view.get_mut(entity)
}
pub fn contains(&self, entity: Entity) -> bool {
self.view.contains(entity)
}
pub unsafe fn get_unchecked(&self, entity: Entity) -> Option<Q::Item<'_>> {
self.view.get_unchecked(entity)
}
pub fn get_disjoint_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
self.view.get_disjoint_mut(entities)
}
#[doc(hidden)]
#[deprecated(since = "0.11.0", note = "renamed to `get_disjoint_mut`")]
pub fn get_many_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> [Option<Q::Item<'_>>; N] {
self.view.get_disjoint_mut(entities)
}
pub fn iter_mut(&mut self) -> ViewIter<'_, Q> {
self.view.iter_mut()
}
}
impl<Q: Query> Drop for ViewBorrow<'_, Q> {
fn drop(&mut self) {
self.cache.release_borrow(self.view.archetypes);
}
}
impl<'a, Q: Query> IntoIterator for &'a mut ViewBorrow<'_, Q> {
type IntoIter = ViewIter<'a, Q>;
type Item = Q::Item<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
pub(crate) fn assert_distinct<const N: usize>(entities: &[Entity; N]) {
match N {
1 => (),
2 => assert_ne!(entities[0], entities[1]),
3 => {
assert_ne!(entities[0], entities[1]);
assert_ne!(entities[1], entities[2]);
assert_ne!(entities[2], entities[0]);
}
_ => {
let mut entities = *entities;
entities.sort_unstable();
for index in 0..N - 1 {
assert_ne!(entities[index], entities[index + 1]);
}
}
}
}
#[cfg(feature = "std")]
pub(crate) type QueryCache = RwLock<TypeIdMap<Arc<dyn Any + Send + Sync>>>;
#[cfg(feature = "std")]
struct CachedQueryInner<F: Fetch> {
state: Box<[(usize, F::State)]>,
archetypes_generation: crate::ArchetypesGeneration,
}
#[cfg(feature = "std")]
impl<F: Fetch> CachedQueryInner<F> {
fn new(world: &World) -> Self {
Self {
state: world
.archetypes()
.enumerate()
.filter_map(|(idx, x)| F::prepare(x).map(|state| (idx, state)))
.collect(),
archetypes_generation: world.archetypes_generation(),
}
}
}
pub(crate) struct CachedQuery<F: Fetch> {
#[cfg(feature = "std")]
inner: Arc<CachedQueryInner<F>>,
#[cfg(not(feature = "std"))]
_marker: PhantomData<F>,
}
impl<F: Fetch> CachedQuery<F> {
pub(crate) fn get(world: &World) -> Self {
#[cfg(feature = "std")]
{
let existing_cache = world
.query_cache()
.read()
.unwrap()
.get(&TypeId::of::<F>())
.map(|x| Arc::downcast::<CachedQueryInner<F>>(x.clone()).unwrap())
.filter(|x| x.archetypes_generation == world.archetypes_generation());
let inner = existing_cache.unwrap_or_else(
#[cold]
|| {
let mut cache = world.query_cache().write().unwrap();
let entry = cache.entry(TypeId::of::<F>());
let cached = match entry {
hash_map::Entry::Vacant(e) => {
let fresh = Arc::new(CachedQueryInner::<F>::new(world));
e.insert(fresh.clone());
fresh
}
hash_map::Entry::Occupied(mut e) => {
let value =
Arc::downcast::<CachedQueryInner<F>>(e.get().clone()).unwrap();
match value.archetypes_generation == world.archetypes_generation() {
false => {
let fresh = Arc::new(CachedQueryInner::<F>::new(world));
e.insert(fresh.clone());
fresh
}
true => value,
}
}
};
cached
},
);
Self { inner }
}
#[cfg(not(feature = "std"))]
{
_ = world;
Self {
_marker: PhantomData,
}
}
}
fn archetype_count(&self, archetypes: &[Archetype]) -> usize {
#[cfg(feature = "std")]
{
_ = archetypes;
self.inner.state.len()
}
#[cfg(not(feature = "std"))]
{
archetypes.len()
}
}
unsafe fn get_state<'a>(
&self,
archetypes: &'a [Archetype],
index: usize,
) -> Option<(&'a Archetype, F::State)> {
#[cfg(feature = "std")]
unsafe {
let &(archetype, state) = self.inner.state.get_unchecked(index);
let archetype = archetypes.get_unchecked(archetype);
Some((archetype, state))
}
#[cfg(not(feature = "std"))]
{
let archetype = unsafe { archetypes.get_unchecked(index) };
let state = F::prepare(archetype)?;
Some((archetype, state))
}
}
unsafe fn get_archetype<'a>(
&self,
archetypes: &'a [Archetype],
index: usize,
) -> Option<&'a Archetype> {
#[cfg(feature = "std")]
unsafe {
let &(archetype, _) = self.inner.state.get_unchecked(index);
let archetype = archetypes.get_unchecked(archetype);
Some(archetype)
}
#[cfg(not(feature = "std"))]
{
let x = unsafe { archetypes.get_unchecked(index) };
if F::access(x).is_none() {
return None;
}
Some(x)
}
}
fn borrow(&self, archetypes: &[Archetype]) {
#[cfg(feature = "std")]
{
for &(archetype, state) in &self.inner.state {
let archetype = unsafe { archetypes.get_unchecked(archetype) };
if archetype.is_empty() {
continue;
}
F::borrow(archetype, state);
}
}
#[cfg(not(feature = "std"))]
{
for x in archetypes {
if x.is_empty() {
continue;
}
if let Some(state) = F::prepare(x) {
F::borrow(x, state);
}
}
}
}
fn release_borrow(&self, archetypes: &[Archetype]) {
#[cfg(feature = "std")]
{
for &(archetype, state) in &self.inner.state {
let archetype = unsafe { archetypes.get_unchecked(archetype) };
if archetype.is_empty() {
continue;
}
F::release(archetype, state);
}
}
#[cfg(not(feature = "std"))]
{
for x in archetypes {
if x.is_empty() {
continue;
}
if let Some(state) = F::prepare(x) {
F::release(x, state);
}
}
}
}
fn fetch_all(&self, archetypes: &[Archetype]) -> Box<[Option<F>]> {
#[cfg(feature = "std")]
{
let mut fetch = (0..archetypes.len()).map(|_| None).collect::<Box<[_]>>();
for &(archetype_index, state) in &self.inner.state {
let archetype = &archetypes[archetype_index];
fetch[archetype_index] = Some(F::execute(archetype, state));
}
fetch
}
#[cfg(not(feature = "std"))]
{
archetypes
.iter()
.map(|archetype| F::prepare(archetype).map(|state| F::execute(archetype, state)))
.collect()
}
}
}
impl<F: Fetch> Clone for CachedQuery<F> {
fn clone(&self) -> Self {
Self {
#[cfg(feature = "std")]
inner: self.inner.clone(),
#[cfg(not(feature = "std"))]
_marker: PhantomData,
}
}
}
struct ArchetypeIter<Q: Query> {
archetypes: core::ops::Range<usize>,
cache: CachedQuery<Q::Fetch>,
}
impl<Q: Query> ArchetypeIter<Q> {
fn new(world: &World, cache: CachedQuery<Q::Fetch>) -> Self {
Self {
archetypes: 0..cache.archetype_count(world.archetypes_inner()),
cache,
}
}
unsafe fn next(&mut self, world: &World) -> Option<ChunkIter<Q>> {
loop {
let Some((archetype, state)) = self
.cache
.get_state(world.archetypes_inner(), self.archetypes.next()?)
else {
continue;
};
let fetch = Q::Fetch::execute(archetype, state);
return Some(ChunkIter::new(archetype, fetch));
}
}
fn entity_len(&self, world: &World) -> usize {
self.archetypes
.clone()
.filter_map(|x| unsafe { self.cache.get_archetype(world.archetypes_inner(), x) })
.map(|x| x.len() as usize)
.sum()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn access_order() {
assert!(Access::Write > Access::Read);
assert!(Access::Read > Access::Iterate);
assert!(Some(Access::Iterate) > None);
}
}