cecs 0.1.11

Entity database for the game 'Cao-Lo'
Documentation
use std::{
    any::TypeId,
    collections::HashSet,
    fmt::Debug,
    marker::PhantomData,
    ops::{Deref, DerefMut},
};

use super::WorldQuery;

pub struct Res<'a, T> {
    inner: &'a T,
    _m: PhantomData<T>,
}

impl<'a, T> Debug for Res<'a, T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Res").field("inner", &self.inner).finish()
    }
}

unsafe impl<'a, T: 'static> WorldQuery<'a> for Res<'a, T> {
    fn new(db: &'a crate::World, _system_idx: usize) -> Self {
        Self::new(db)
    }

    fn resources_const(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }

    fn read_only() -> bool {
        true
    }
}

impl<'a, T: 'static> Res<'a, T> {
    pub fn new(world: &'a crate::World) -> Self {
        let inner = match world.resources.fetch() {
            Some(inner) => inner,
            None => {
                panic!(
                    "Res query on uninitialized type: {}",
                    std::any::type_name::<T>()
                );
            }
        };
        Self {
            inner,
            _m: PhantomData,
        }
    }

    pub fn cloned(&self) -> T
    where
        T: Clone,
    {
        self.inner.clone()
    }

    pub fn copied(&self) -> T
    where
        T: Copy,
    {
        *self.inner
    }
}

impl<'a, T: 'static> Deref for Res<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.inner
    }
}

impl<'a, T: 'static> AsRef<T> for Res<'a, T> {
    fn as_ref(&self) -> &T {
        self.inner
    }
}

pub struct ResMut<'a, T> {
    inner: &'a mut T,
    _m: PhantomData<fn() -> &'a mut T>,
}
impl<'a, T> Debug for ResMut<'a, T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ResMut")
            .field("inner", &self.inner)
            .finish()
    }
}
impl<'a, T: 'static> ResMut<'a, T> {
    pub fn new(world: &'a crate::World) -> Self {
        let inner = match unsafe { world.resources.fetch_mut() } {
            Some(inner) => inner,
            None => {
                panic!(
                    "ResMut query on uninitialized type: {}",
                    std::any::type_name::<T>()
                );
            }
        };
        Self {
            inner,
            _m: PhantomData,
        }
    }

    pub fn cloned(&self) -> T
    where
        T: Clone,
    {
        self.inner.clone()
    }

    pub fn copied(&self) -> T
    where
        T: Copy,
    {
        *self.inner
    }
}

impl<'a, T: 'static> Deref for ResMut<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.inner
    }
}

impl<'a, T: 'static> DerefMut for ResMut<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner
    }
}

impl<'a, T: 'static> AsRef<T> for ResMut<'a, T> {
    fn as_ref(&self) -> &T {
        self.inner
    }
}

impl<'a, T: 'static> AsMut<T> for ResMut<'a, T> {
    fn as_mut(&mut self) -> &mut T {
        self.inner
    }
}

unsafe impl<'a, T: 'static> WorldQuery<'a> for ResMut<'a, T> {
    fn new(db: &'a crate::World, _system_idx: usize) -> Self {
        Self::new(db)
    }

    fn resources_mut(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }

    fn resources_const(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }
}

unsafe impl<'a, T: 'static> WorldQuery<'a> for Option<Res<'a, T>> {
    fn new(world: &'a crate::World, _system_idx: usize) -> Self {
        let inner = world.resources.fetch();
        inner.map(|inner| Res {
            inner,
            _m: PhantomData,
        })
    }

    fn resources_const(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }

    fn read_only() -> bool {
        true
    }
}

unsafe impl<'a, T: 'static> WorldQuery<'a> for Option<ResMut<'a, T>> {
    fn new(world: &'a crate::World, _system_idx: usize) -> Self {
        let inner = unsafe { world.resources.fetch_mut() };
        inner.map(|inner| ResMut {
            inner,
            _m: PhantomData,
        })
    }

    fn resources_mut(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }

    fn resources_const(set: &mut HashSet<TypeId>) {
        set.insert(TypeId::of::<T>());
    }
}

#[cfg(test)]
mod tests {
    use crate::World;

    use super::*;

    #[test]
    fn test_tuple_resource_query() {
        let mut world = World::new(4);

        world.insert_resource(1i32);
        world.insert_resource(2u32);

        world.run_view_system(|(i, u): (Res<i32>, Res<u32>)| {
            assert_eq!(*i, 1);
            assert_eq!(*u, 2);
        });
    }
}