use core::any::TypeId;
use crate::{
archetype::Archetype, component::ComponentInfo, epoch::EpochId, system::QueryArg, type_id,
};
use super::{
fetch::UnitFetch, Access, AsQuery, DefaultQuery, Fetch, ImmutableQuery, IntoQuery, Query,
SendQuery, WriteAlias,
};
#[derive(Clone, Copy, Debug)]
pub struct FilteredFetch<F, Q> {
filter: F,
query: Q,
}
unsafe impl<'a, F, Q> Fetch<'a> for FilteredFetch<F, Q>
where
F: Fetch<'a>,
Q: Fetch<'a>,
{
type Item = Q::Item;
#[inline(always)]
fn dangling() -> Self {
FilteredFetch {
filter: F::dangling(),
query: Q::dangling(),
}
}
#[inline(always)]
unsafe fn visit_chunk(&mut self, chunk_idx: u32) -> bool {
self.filter.visit_chunk(chunk_idx) && self.query.visit_chunk(chunk_idx)
}
#[inline(always)]
unsafe fn touch_chunk(&mut self, chunk_idx: u32) {
self.filter.touch_chunk(chunk_idx);
self.query.touch_chunk(chunk_idx);
}
#[inline(always)]
unsafe fn visit_item(&mut self, idx: u32) -> bool {
self.filter.visit_item(idx) && self.query.visit_item(idx)
}
#[inline(always)]
unsafe fn get_item(&mut self, idx: u32) -> Self::Item {
self.query.get_item(idx)
}
}
#[derive(Clone, Copy)]
pub struct Not<T>(pub T);
pub enum NotFetch<T> {
Fetch { fetch: T, visit_chunk: bool },
None,
}
unsafe impl<'a, T> Fetch<'a> for NotFetch<T>
where
T: Fetch<'a>,
{
type Item = ();
#[inline(always)]
fn dangling() -> Self {
NotFetch::None
}
#[inline(always)]
unsafe fn visit_chunk(&mut self, chunk_idx: u32) -> bool {
match self {
NotFetch::Fetch { fetch, visit_chunk } => *visit_chunk = fetch.visit_chunk(chunk_idx),
NotFetch::None => {}
}
true
}
#[inline(always)]
unsafe fn touch_chunk(&mut self, _chunk_idx: u32) {}
#[inline(always)]
unsafe fn visit_item(&mut self, idx: u32) -> bool {
match self {
NotFetch::Fetch { fetch, visit_chunk } if *visit_chunk => fetch.visit_item(idx),
_ => true,
}
}
#[inline(always)]
unsafe fn get_item(&mut self, _idx: u32) {}
}
impl<T> AsQuery for Not<T>
where
T: AsQuery,
{
type Query = Not<T::Query>;
}
impl<T> IntoQuery for Not<T>
where
T: IntoQuery,
{
#[inline(always)]
fn into_query(self) -> Not<T::Query> {
Not(self.0.into_query())
}
}
impl<T> DefaultQuery for Not<T>
where
T: DefaultQuery,
{
#[inline(always)]
fn default_query() -> Not<T::Query> {
Not(T::default_query())
}
}
impl<T> QueryArg for Not<T>
where
T: QueryArg,
{
#[inline(always)]
fn new() -> Not<T::Query> {
Not(T::new())
}
}
unsafe impl<T> Query for Not<T>
where
T: Query,
{
type Item<'a> = ();
type Fetch<'a> = NotFetch<T::Fetch<'a>> where T: 'a;
const MUTABLE: bool = T::MUTABLE;
#[inline(always)]
fn component_access(&self, _comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
Ok(None)
}
#[inline(always)]
fn visit_archetype(&self, archetype: &Archetype) -> bool {
if T::FILTERS_ENTITIES {
true
} else {
!self.0.visit_archetype(archetype)
}
}
#[inline(always)]
unsafe fn access_archetype(&self, _archetype: &Archetype, _f: impl FnMut(TypeId, Access)) {}
#[inline(always)]
unsafe fn fetch<'a>(
&self,
arch_idx: u32,
archetype: &'a Archetype,
epoch: EpochId,
) -> NotFetch<T::Fetch<'a>> {
if self.0.visit_archetype(archetype) {
NotFetch::Fetch {
fetch: self.0.fetch(arch_idx, archetype, epoch),
visit_chunk: false,
}
} else {
NotFetch::None
}
}
}
unsafe impl<T> ImmutableQuery for Not<T> where T: ImmutableQuery {}
unsafe impl<T> SendQuery for Not<T> where T: SendQuery {}
marker_type! {
pub struct With<T>;
}
impl<T> AsQuery for With<T>
where
T: 'static,
{
type Query = Self;
}
impl<T> IntoQuery for With<T>
where
T: 'static,
{
#[inline(always)]
fn into_query(self) -> Self {
self
}
}
impl<T> DefaultQuery for With<T>
where
T: 'static,
{
#[inline(always)]
fn default_query() -> Self {
With
}
}
impl<T> QueryArg for With<T>
where
T: 'static,
{
#[inline(always)]
fn new() -> With<T> {
With
}
}
unsafe impl<T> Query for With<T>
where
T: 'static,
{
type Item<'a> = ();
type Fetch<'a> = UnitFetch;
const MUTABLE: bool = false;
#[inline(always)]
fn component_access(&self, _comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias> {
Ok(None)
}
#[inline(always)]
fn visit_archetype(&self, archetype: &Archetype) -> bool {
archetype.has_component(type_id::<T>())
}
#[inline(always)]
unsafe fn access_archetype(&self, _archetype: &Archetype, _f: impl FnMut(TypeId, Access)) {}
#[inline(always)]
unsafe fn fetch(&self, _: u32, _: &Archetype, _: EpochId) -> UnitFetch {
UnitFetch::new()
}
}
unsafe impl<T> ImmutableQuery for With<T> where T: 'static {}
unsafe impl<T> SendQuery for With<T> where T: 'static {}
pub type Without<T> = Not<With<T>>;