use std::marker::PhantomData;
use super::{
filter::{and::And, EntityFilter, EntityFilterTuple},
QueryResult,
};
use crate::internals::{
iter::{
indexed::{IndexedIter, TrustedRandomAccess},
map::MapInto,
zip::{multizip, Zip},
},
permissions::Permissions,
storage::{
archetype::Archetype,
component::{Component, ComponentTypeId},
Components,
},
subworld::ComponentAccess,
};
pub mod entity;
pub mod read;
pub mod try_read;
pub mod try_write;
pub mod write;
pub trait IntoView {
type View: for<'a> View<'a> + 'static;
}
impl<'a, T: Component> IntoView for &'a T {
type View = read::Read<T>;
}
impl<'a, T: Component> IntoView for &'a mut T {
type View = write::Write<T>;
}
impl<'a, T: Component> IntoView for Option<&'a T> {
type View = try_read::TryRead<T>;
}
impl<'a, T: Component> IntoView for Option<&'a mut T> {
type View = try_write::TryWrite<T>;
}
pub trait DefaultFilter {
type Filter: EntityFilter + 'static;
}
pub trait View<'data>: DefaultFilter + Sized {
type Element: Send + Sync + 'data;
type Fetch: Fetch + IntoIndexableIter<Item = Self::Element> + 'data;
type Iter: Iterator<Item = Option<Self::Fetch>> + 'data;
type Read: AsRef<[ComponentTypeId]>;
type Write: AsRef<[ComponentTypeId]>;
unsafe fn fetch(
components: &'data Components,
archetypes: &'data [Archetype],
query: QueryResult<'data>,
) -> Self::Iter;
fn validate();
fn validate_access(access: &ComponentAccess) -> bool;
fn reads_types() -> Self::Read;
fn writes_types() -> Self::Write;
fn reads<T: Component>() -> bool;
fn writes<T: Component>() -> bool;
fn requires_permissions() -> Permissions<ComponentTypeId>;
}
#[doc(hidden)]
pub trait IntoIndexableIter {
type Item: Send + Sync;
type IntoIter: Iterator<Item = Self::Item>
+ TrustedRandomAccess<Item = Self::Item>
+ Send
+ Sync;
fn into_indexable_iter(self) -> Self::IntoIter;
}
pub trait Fetch: IntoIndexableIter + Send + Sync {
type Data;
fn into_components(self) -> Self::Data;
fn find<T: 'static>(&self) -> Option<&[T]>;
fn find_mut<T: 'static>(&mut self) -> Option<&mut [T]>;
fn version<T: Component>(&self) -> Option<u64>;
fn accepted(&mut self);
}
pub unsafe trait ReadOnlyFetch: Fetch {
fn get_components(&self) -> Self::Data;
}
#[doc(hidden)]
pub unsafe trait ReadOnly {}
unsafe impl<T> ReadOnly for &T {}
unsafe impl<T> ReadOnly for Option<&T> {}
#[doc(hidden)]
pub struct MultiFetch<'a, T> {
fetches: T,
_phantom: PhantomData<&'a T>,
}
macro_rules! view_tuple {
($head_ty:ident) => {
impl_view_tuple!($head_ty);
};
($head_ty:ident, $( $tail_ty:ident ),*) => (
impl_view_tuple!($head_ty, $( $tail_ty ),*);
view_tuple!($( $tail_ty ),*);
);
}
macro_rules! impl_view_tuple {
( $( $ty: ident ),* ) => {
unsafe impl<$( $ty: ReadOnly ),*> ReadOnly for ($( $ty, )*) {}
impl<$( $ty: DefaultFilter ),*> DefaultFilter for ($( $ty, )*) {
type Filter = EntityFilterTuple<
And<($( <$ty::Filter as EntityFilter>::Layout, )*)>,
And<($( <$ty::Filter as EntityFilter>::Dynamic, )*)>
>;
}
impl<$( $ty: IntoView ),*> IntoView for ($( $ty, )*) {
type View = ($( $ty::View, )*);
}
impl<'a, $( $ty: View<'a> + 'a ),*> View<'a> for ($( $ty, )*) {
type Element = <Self::Fetch as IntoIndexableIter>::Item;
type Fetch = MultiFetch<'a, ($( $ty::Fetch, )*)>;
type Iter = MapInto<Zip<($( $ty::Iter, )*)>, Option<MultiFetch<'a, ($( $ty::Fetch, )*)>>>;
type Read = Vec<ComponentTypeId>;
type Write = Vec<ComponentTypeId>;
unsafe fn fetch(
components: &'a Components,
archetypes: &'a [Archetype],
query: QueryResult<'a>,
) -> Self::Iter {
MapInto::new(
multizip(
(
$( $ty::fetch(components, archetypes, query.clone()), )*
)
)
)
}
paste::item! {
fn validate() {
#![allow(non_snake_case)]
$( let [<$ty _reads>] = $ty::reads_types(); )*
$( let [<$ty _writes>] = $ty::writes_types(); )*
let reads = [$( [<$ty _reads>].as_ref(), )*];
let writes = [$( [<$ty _writes>].as_ref(), )*];
for (i, writes) in writes.iter().enumerate() {
for (j, other_reads) in reads.iter().enumerate() {
if i == j { continue; }
for w in writes.iter() {
assert!(!other_reads.iter().any(|x| x == w));
}
}
}
}
fn validate_access(access: &ComponentAccess) -> bool {
$( $ty::validate_access(access) )&&*
}
fn reads_types() -> Self::Read {
#![allow(non_snake_case)]
let types = std::iter::empty();
$( let [<$ty _reads>] = $ty::reads_types(); )*
$( let types = types.chain([<$ty _reads>].as_ref().iter()); )*
types.copied().collect()
}
fn writes_types() -> Self::Write {
#![allow(non_snake_case)]
let types = std::iter::empty();
$( let [<$ty _writes>] = $ty::writes_types(); )*
$( let types = types.chain([<$ty _writes>].as_ref().iter()); )*
types.copied().collect()
}
fn requires_permissions() -> Permissions<ComponentTypeId> {
let mut permissions = Permissions::new();
$( permissions.add($ty::requires_permissions()); )*
permissions
}
}
fn reads<Comp: Component>() -> bool {
$(
$ty::reads::<Comp>()
)||*
}
fn writes<Comp: Component>() -> bool {
$(
$ty::writes::<Comp>()
)||*
}
}
impl<'a, $( $ty: Fetch ),*> crate::internals::iter::map::From<($( Option<$ty>, )*)>
for Option<MultiFetch<'a, ($( $ty, )*)>>
{
fn from(value: ($( Option<$ty>, )*)) -> Self {
#[allow(non_snake_case)]
let ($( $ty, )*) = value;
let valid = $( $ty.is_some() )&*;
if valid {
Some(MultiFetch {
fetches: ($( $ty.unwrap(), )*),
_phantom: PhantomData
})
} else {
None
}
}
}
impl<'a, $( $ty: Fetch ),*> IntoIndexableIter for MultiFetch<'a, ($( $ty, )*)> {
type IntoIter = IndexedIter<($( $ty::IntoIter, )*)>;
type Item = <Self::IntoIter as Iterator>::Item;
fn into_indexable_iter(self) -> Self::IntoIter {
#[allow(non_snake_case)]
let ($( $ty, )*) = self.fetches;
IndexedIter::new(($( $ty.into_indexable_iter(), )*))
}
}
impl<'a, $( $ty: Fetch ),*> IntoIterator for MultiFetch<'a, ($( $ty, )*)> {
type IntoIter = <Self as IntoIndexableIter>::IntoIter;
type Item = <Self as IntoIndexableIter>::Item;
fn into_iter(self) -> Self::IntoIter {
self.into_indexable_iter()
}
}
unsafe impl<'a, $( $ty: ReadOnlyFetch),*> ReadOnlyFetch for MultiFetch<'a, ($( $ty, )*)>
{
fn get_components(&self) -> Self::Data {
#[allow(non_snake_case)]
let ($( $ty, )*) = &self.fetches;
(($( $ty.get_components(), )*))
}
}
impl<'a, $( $ty: Fetch ),*> Fetch for MultiFetch<'a, ($( $ty, )*)> {
type Data = ($( $ty::Data, )*);
#[inline]
fn into_components(self) -> Self::Data {
#[allow(non_snake_case)]
let ($( $ty, )*) = self.fetches;
($( $ty.into_components(), )*)
}
#[inline]
fn find<Comp: 'static>(&self) -> Option<&[Comp]> {
#[allow(non_snake_case)]
let ($( $ty, )*) = &self.fetches;
let mut result = None;
$(
result = result.or_else(|| $ty.find());
)*
result
}
#[inline]
fn find_mut<Comp: 'static>(&mut self) -> Option<&mut [Comp]> {
#[allow(non_snake_case)]
let ($( $ty, )*) = &mut self.fetches;
let mut result = None;
$(
result = result.or_else(move || $ty.find_mut());
)*
result
}
#[inline]
fn version<Comp: Component>(&self) -> Option<u64> {
#[allow(non_snake_case)]
let ($( $ty, )*) = &self.fetches;
let mut result = None;
$(
result = result.or_else(|| $ty.version::<Comp>());
)*
result
}
#[inline]
fn accepted(&mut self) {
#[allow(non_snake_case)]
let ($( $ty, )*) = &mut self.fetches;
$( $ty.accepted(); )*
}
}
};
}
#[cfg(feature = "extended-tuple-impls")]
view_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
#[cfg(not(feature = "extended-tuple-impls"))]
view_tuple!(A, B, C, D, E, F, G, H);