mod as_deref;
mod cloned;
mod component;
mod component_mut;
mod copied;
mod entity_ref;
mod ext;
mod map;
mod maybe_mut;
mod opt;
mod read_only;
mod relations;
mod relations_mut;
mod satisfied;
mod source;
mod transform;
use crate::{
archetype::{Archetype, ArchetypeId, Slice, Slot},
filter::{RefFetch, StaticFilter},
system::Access,
util::Ptr,
ArchetypeSearcher, Entity, World,
};
use alloc::vec::Vec;
use core::fmt::Debug;
use core::fmt::{self, Formatter};
pub use as_deref::*;
pub use cloned::*;
pub use component::*;
pub use component_mut::*;
pub use entity_ref::*;
pub use ext::FetchExt;
pub use map::Map;
pub use maybe_mut::{MaybeMut, MutGuard};
pub use opt::*;
pub use read_only::*;
pub use relations::{nth_relation, relations_like, NthRelation, Relations, RelationsIter};
pub use relations_mut::{relations_like_mut, RelationsIterMut, RelationsMut};
pub use satisfied::Satisfied;
pub use source::Source;
pub use transform::{Added, Modified, TransformFetch};
#[doc(hidden)]
pub struct FmtQuery<'r, Q>(pub &'r Q);
impl<'r, 'w, Q> Debug for FmtQuery<'r, Q>
where
Q: Fetch<'w>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.describe(f)
}
}
#[derive(Copy, Clone)]
pub struct FetchAccessData<'w> {
pub world: &'w World,
pub arch: &'w Archetype,
pub arch_id: ArchetypeId,
}
impl<'w> From<FetchPrepareData<'w>> for FetchAccessData<'w> {
fn from(value: FetchPrepareData<'w>) -> Self {
Self {
world: value.world,
arch: value.arch,
arch_id: value.arch_id,
}
}
}
#[derive(Copy, Clone)]
pub struct FetchPrepareData<'w> {
pub world: &'w World,
pub arch: &'w Archetype,
pub arch_id: ArchetypeId,
pub old_tick: u32,
pub new_tick: u32,
}
pub trait FetchItem<'q> {
type Item;
}
pub trait Fetch<'w>: for<'q> FetchItem<'q> {
const MUTABLE: bool;
type Prepared: for<'x> PreparedFetch<'x, Item = <Self as FetchItem<'x>>::Item> + 'w;
fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared>;
fn filter_arch(&self, data: FetchAccessData) -> bool;
fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>);
fn describe(&self, f: &mut Formatter<'_>) -> fmt::Result;
#[inline]
fn searcher(&self, _searcher: &mut ArchetypeSearcher) {}
#[inline]
fn by_ref(&self) -> RefFetch<Self>
where
Self: Sized,
{
RefFetch(self)
}
}
pub trait PreparedFetch<'q> {
type Item: 'q;
type Chunk: 'q;
const HAS_FILTER: bool;
unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk;
unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item;
#[inline]
unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
slots
}
}
pub trait UnionFilter {
const HAS_UNION_FILTER: bool;
unsafe fn filter_union(&mut self, slots: Slice) -> Slice;
}
impl<'q, F> PreparedFetch<'q> for &'q mut F
where
F: PreparedFetch<'q>,
{
type Item = F::Item;
type Chunk = F::Chunk;
const HAS_FILTER: bool = F::HAS_FILTER;
unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
(*self).create_chunk(slots)
}
unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
F::fetch_next(chunk)
}
unsafe fn filter_slots(&mut self, slots: Slice) -> Slice {
(*self).filter_slots(slots)
}
}
impl<'q> FetchItem<'q> for () {
type Item = ();
}
impl UnionFilter for () {
const HAS_UNION_FILTER: bool = false;
unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
slots
}
}
impl<'w> Fetch<'w> for () {
const MUTABLE: bool = false;
type Prepared = ();
fn prepare(&self, _: FetchPrepareData<'w>) -> Option<Self::Prepared> {
Some(())
}
fn filter_arch(&self, _: FetchAccessData) -> bool {
true
}
fn describe(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "()")
}
#[inline]
fn access(&self, _: FetchAccessData, _: &mut Vec<Access>) {}
}
impl<'q> RandomFetch<'q> for () {
#[inline]
unsafe fn fetch_shared(&'q self, _: Slot) -> Self::Item {}
#[inline]
unsafe fn fetch_shared_chunk(_: &Self::Chunk, _: Slot) -> Self::Item {}
}
impl<'q> PreparedFetch<'q> for () {
type Item = ();
type Chunk = ();
const HAS_FILTER: bool = false;
#[inline]
unsafe fn create_chunk(&'q mut self, _: Slice) -> Self::Chunk {}
#[inline]
unsafe fn fetch_next(_: &mut Self::Chunk) -> Self::Item {}
}
#[derive(Debug, Clone)]
pub struct EntityIds;
#[doc(hidden)]
pub struct ReadEntities<'a> {
entities: &'a [Entity],
}
impl<'q> FetchItem<'q> for EntityIds {
type Item = Entity;
}
impl<'w> Fetch<'w> for EntityIds {
const MUTABLE: bool = false;
type Prepared = ReadEntities<'w>;
fn prepare(&self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
Some(ReadEntities {
entities: data.arch.entities(),
})
}
fn filter_arch(&self, _: FetchAccessData) -> bool {
true
}
fn describe(&self, f: &mut Formatter) -> fmt::Result {
f.write_str("entity_ids")
}
#[inline]
fn access(&self, _: FetchAccessData, _: &mut Vec<Access>) {}
}
impl<'w, 'q> PreparedFetch<'q> for ReadEntities<'w> {
type Item = Entity;
type Chunk = Ptr<'q, Entity>;
const HAS_FILTER: bool = false;
unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
Ptr::new(self.entities[slots.as_range()].as_ptr())
}
unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
let old = chunk.as_ptr();
*chunk = chunk.add(1);
*old
}
}
impl<'w, 'q> RandomFetch<'q> for ReadEntities<'w> {
#[inline]
unsafe fn fetch_shared(&self, slot: usize) -> Self::Item {
self.entities[slot]
}
unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {
*chunk.add(slot).as_ref()
}
}
macro_rules! tuple_impl {
($($idx: tt => $ty: ident),*) => {
impl<'q, $($ty, )*> FetchItem<'q> for ($($ty,)*)
where $($ty: FetchItem<'q>,)*
{
type Item = ($($ty::Item,)*);
}
impl<'q, $($ty, )*> RandomFetch<'q> for ($($ty,)*)
where $($ty: RandomFetch<'q>,)*
{
#[inline(always)]
unsafe fn fetch_shared(&'q self, slot: Slot) -> Self::Item {
($(
(self.$idx).fetch_shared(slot),
)*)
}
#[inline(always)]
unsafe fn fetch_shared_chunk(chunk: &Self::Chunk, slot: Slot) -> Self::Item {
($(
$ty::fetch_shared_chunk(&chunk.$idx, slot),
)*)
}
}
impl<'q, $($ty, )*> PreparedFetch<'q> for ($($ty,)*)
where $($ty: PreparedFetch<'q>,)*
{
type Item = ($($ty::Item,)*);
type Chunk = ($($ty::Chunk,)*);
const HAS_FILTER: bool = $($ty::HAS_FILTER )||*;
#[inline]
unsafe fn fetch_next(chunk: &mut Self::Chunk) -> Self::Item {
($(
$ty::fetch_next(&mut chunk.$idx),
)*)
}
#[inline]
unsafe fn create_chunk(&'q mut self, slots: Slice) -> Self::Chunk {
($((self.$idx).create_chunk(slots),)*)
}
#[inline]
unsafe fn filter_slots(&mut self, mut slots: Slice) -> Slice {
$(
slots = self.$idx.filter_slots(slots);
)*
slots
}
}
impl<'q, $($ty, )*> UnionFilter for ($($ty,)*)
where $($ty: PreparedFetch<'q>,)*
{
const HAS_UNION_FILTER: bool = $($ty::HAS_FILTER )&&*;
#[inline]
unsafe fn filter_union(&mut self, slots: Slice) -> Slice {
[
$( self.$idx.filter_slots(slots)),*
]
.into_iter()
.min()
.unwrap_or_default()
}
}
impl<'w, $($ty, )*> Fetch<'w> for ($($ty,)*)
where $($ty: Fetch<'w>,)*
{
const MUTABLE: bool = $($ty::MUTABLE )||*;
type Prepared = ($($ty::Prepared,)*);
#[inline]
fn prepare(&'w self, data: FetchPrepareData<'w>) -> Option<Self::Prepared> {
Some( ($( (self.$idx).prepare(data)?,)*) )
}
#[inline]
fn filter_arch(&self, data:FetchAccessData) -> bool {
( $((self.$idx).filter_arch(data)) && * )
}
#[inline]
fn describe(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(&($(FmtQuery(&self.$idx),)*), f)
}
#[inline]
fn access(&self, data: FetchAccessData, dst: &mut Vec<Access>) {
$( (self.$idx).access(data, dst);)*
}
#[inline]
fn searcher(&self, searcher: &mut ArchetypeSearcher) {
$((self.$idx).searcher(searcher));*
}
}
impl< $($ty: StaticFilter, )*> StaticFilter for ($($ty,)*)
{
fn filter_static(&self, arch: &Archetype) -> bool {
( $((self.$idx).filter_static(arch)) && * )
}
}
};
}
tuple_impl! { 0 => A }
tuple_impl! { 0 => A, 1 => B }
tuple_impl! { 0 => A, 1 => B, 2 => C }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H, 7 => I }
tuple_impl! { 0 => A, 1 => B, 2 => C, 3 => D, 4 => E, 5 => F, 6 => H, 7 => I, 8 => J }