geng-ecs 0.11.0

Game Engine (ecs)
Documentation
use super::*;

pub trait Filter {
    type Fetch: for<'a> Fetch<'a>;
    fn fetch(self) -> Self::Fetch;
    unsafe fn get_world<'a>(
        fetch: &Self::Fetch,
        borrows: &<Self::Fetch as Fetch<'a>>::WorldBorrows,
        id: Id,
    ) -> bool;
    unsafe fn get<'a>(
        fetch: &Self::Fetch,
        borrows: &<Self::Fetch as Fetch<'a>>::DirectBorrows,
    ) -> bool;
}

pub trait FetchBool {
    type Fetch: for<'a> Fetch<'a, Output = bool>;
    fn fetch(self) -> Self::Fetch;
}

impl<T: FetchBool> Filter for T {
    type Fetch = <T as FetchBool>::Fetch;

    fn fetch(self) -> Self::Fetch {
        <T as FetchBool>::fetch(self)
    }

    unsafe fn get_world<'a>(
        fetch: &Self::Fetch,
        borrows: &<Self::Fetch as Fetch<'a>>::WorldBorrows,
        id: Id,
    ) -> bool {
        fetch.get_world(borrows, id).unwrap()
    }

    unsafe fn get<'a>(
        fetch: &Self::Fetch,
        borrows: &<Self::Fetch as Fetch<'a>>::DirectBorrows,
    ) -> bool {
        fetch.get(borrows)
    }
}

impl<F: for<'a> Fetch<'a, Output = bool>> FetchBool for F {
    type Fetch = Self;
    fn fetch(self) -> Self {
        self
    }
}

#[derive(Default)]
pub struct Is<F>(pub F);

impl<F: Filter> FetchBool for Is<F> {
    type Fetch = FilterFetch<F>;
    fn fetch(self) -> Self::Fetch {
        FilterFetch(self.0.fetch())
    }
}

#[derive(Default)]
pub struct And<A, B>(pub A, pub B);

unsafe impl<'a, A: Fetch<'a, Output = bool>, B: Fetch<'a, Output = bool>> Fetch<'a> for And<A, B> {
    type Output = bool;
    type WorldBorrows = (A::WorldBorrows, B::WorldBorrows);
    unsafe fn borrow_world(&self, world: &'a World) -> Option<Self::WorldBorrows> {
        Some((self.0.borrow_world(world)?, self.1.borrow_world(world)?))
    }
    unsafe fn get_world(&self, borrows: &Self::WorldBorrows, id: Id) -> Option<Self::Output> {
        Some(self.0.get_world(&borrows.0, id)? && self.1.get_world(&borrows.1, id)?)
    }
    type DirectBorrows = (A::DirectBorrows, B::DirectBorrows);
    unsafe fn borrow_direct(&self, entity: &'a Entity) -> Option<Self::DirectBorrows> {
        Some((self.0.borrow_direct(entity)?, self.1.borrow_direct(entity)?))
    }
    unsafe fn get(&self, borrows: &Self::DirectBorrows) -> Self::Output {
        self.0.get(&borrows.0) && self.1.get(&borrows.1)
    }
}

impl<A: Filter, B: Filter> std::ops::BitAnd<Is<B>> for Is<A> {
    type Output = Is<And<A, B>>;

    fn bitand(self, rhs: Is<B>) -> Self::Output {
        Is(And(self.0, rhs.0))
    }
}

#[derive(Default)]
pub struct Or<A, B>(pub A, pub B);

unsafe impl<'a, A: Fetch<'a, Output = bool>, B: Fetch<'a, Output = bool>> Fetch<'a> for Or<A, B> {
    type Output = bool;
    type WorldBorrows = (A::WorldBorrows, B::WorldBorrows);
    unsafe fn borrow_world(&self, world: &'a World) -> Option<Self::WorldBorrows> {
        Some((self.0.borrow_world(world)?, self.1.borrow_world(world)?))
    }
    unsafe fn get_world(&self, borrows: &Self::WorldBorrows, id: Id) -> Option<Self::Output> {
        Some(self.0.get_world(&borrows.0, id)? || self.1.get_world(&borrows.1, id)?)
    }
    type DirectBorrows = (A::DirectBorrows, B::DirectBorrows);
    unsafe fn borrow_direct(&self, entity: &'a Entity) -> Option<Self::DirectBorrows> {
        Some((self.0.borrow_direct(entity)?, self.1.borrow_direct(entity)?))
    }
    unsafe fn get(&self, borrows: &Self::DirectBorrows) -> Self::Output {
        self.0.get(&borrows.0) || self.1.get(&borrows.1)
    }
}

impl<A: Filter, B: Filter> std::ops::BitOr<Is<B>> for Is<A> {
    type Output = Is<Or<A, B>>;

    fn bitor(self, rhs: Is<B>) -> Self::Output {
        Is(Or(self.0, rhs.0))
    }
}

pub struct With<T>(PhantomData<T>);

pub fn with<T: Component>() -> Is<With<T>> {
    Is(With::default())
}

impl<T> Default for With<T> {
    fn default() -> Self {
        Self(PhantomData)
    }
}

unsafe impl<'a, T: Component> Fetch<'a> for With<T> {
    type Output = bool;
    type WorldBorrows = Option<storage::world::Borrow<'a, T>>;
    unsafe fn borrow_world(&self, world: &'a World) -> Option<Self::WorldBorrows> {
        Some(world.borrow::<T>())
    }
    unsafe fn get_world(&self, borrows: &Self::WorldBorrows, id: Id) -> Option<bool> {
        if let Some(borrows) = borrows {
            Some(borrows.get(id).is_some())
        } else {
            Some(false)
        }
    }
    type DirectBorrows = &'a Entity;
    unsafe fn borrow_direct(&self, entity: &'a Entity) -> Option<Self::DirectBorrows> {
        Some(entity)
    }
    unsafe fn get(&self, borrows: &Self::DirectBorrows) -> bool {
        borrows.has::<T>()
    }
}

#[derive(Default)]
pub struct Not<F>(F);

unsafe impl<'a, F: Fetch<'a, Output = bool>> Fetch<'a> for Not<F> {
    type Output = bool;
    type WorldBorrows = F::WorldBorrows;
    unsafe fn borrow_world(&self, world: &'a World) -> Option<Self::WorldBorrows> {
        self.0.borrow_world(world)
    }
    unsafe fn get_world(&self, borrows: &Self::WorldBorrows, id: Id) -> Option<bool> {
        Some(!self.0.get_world(borrows, id)?)
    }
    type DirectBorrows = F::DirectBorrows;
    unsafe fn borrow_direct(&self, entity: &'a Entity) -> Option<Self::DirectBorrows> {
        self.0.borrow_direct(entity)
    }
    unsafe fn get(&self, borrows: &Self::DirectBorrows) -> bool {
        !self.0.get(borrows)
    }
}

impl<A: Filter> std::ops::Not for Is<A> {
    type Output = Is<Not<A>>;
    fn not(self) -> Self::Output {
        Is(Not(self.0))
    }
}

pub type Without<T> = Not<With<T>>;

pub fn without<T: Component>() -> Is<Without<T>> {
    Is(Without::default())
}

pub struct Equal<T>(pub T);

pub fn equal<T>(value: T) -> Is<Equal<T>> {
    Is(Equal(value))
}

unsafe impl<'a, T: Component + PartialEq> Fetch<'a> for Equal<T> {
    type Output = bool;
    type WorldBorrows = <FetchRead<T> as Fetch<'a>>::WorldBorrows;
    unsafe fn borrow_world(&self, world: &'a World) -> Option<Self::WorldBorrows> {
        <FetchRead<T> as Fetch<'a>>::borrow_world(&FetchRead::default(), world)
    }
    unsafe fn get_world(&self, borrows: &Self::WorldBorrows, id: Id) -> Option<Self::Output> {
        borrows.get(id).map(|value| *value == self.0)
    }
    type DirectBorrows = <FetchRead<T> as Fetch<'a>>::DirectBorrows;
    unsafe fn borrow_direct(&self, entity: &'a Entity) -> Option<Self::DirectBorrows> {
        <FetchRead<T> as Fetch<'a>>::borrow_direct(&FetchRead::default(), entity)
    }
    unsafe fn get(&self, borrows: &Self::DirectBorrows) -> Self::Output {
        *borrows.get() == self.0
    }
}

macro_rules! impl_for_tuple {
    ($($name:ident),*) => {
        #[allow(non_camel_case_types)]
        #[allow(unused_variables)]
        #[allow(clippy::unused_unit)]
        impl<$($name: Filter),*> Filter for ($($name,)*) {
            type Fetch = ($($name::Fetch,)*);
            fn fetch(self) -> Self::Fetch {
                let ($($name,)*) = self;
                ($($name.fetch(),)*)
            }
            unsafe fn get_world<'a>(fetch: &Self::Fetch, borrows: &<Self::Fetch as Fetch<'a>>::WorldBorrows, id: Id) -> bool {
                let ($($name,)*) = ZipExt::zip(fetch.as_ref(), borrows.as_ref());
                $(
                    let (fetch, borrows) = $name;
                    if !<$name as Filter>::get_world(fetch, borrows, id) {
                        return false;
                    }
                )*
                true
            }
            unsafe fn get<'a>(fetch: &Self::Fetch, borrows: &<Self::Fetch as Fetch<'a>>::DirectBorrows) -> bool {
                let ($($name,)*) = ZipExt::zip(fetch.as_ref(), borrows.as_ref());
                $(
                    let (fetch, borrows) = $name;
                    if !<$name as Filter>::get(fetch, borrows) {
                        return false;
                    }
                )*
                true
            }
        }
    };
}

impl_tuples!(impl_for_tuple);