dotrix_core 0.5.2

Dotrix 3D game engine core
Documentation
use std::{
    any::{ Any, TypeId },
    collections::HashMap,
};

use super::Archetype;
use crate::ecs::Component;

pub struct Container {
    components: HashMap<TypeId, Box<dyn Stripe>>,
}

trait Stripe: Any {
    fn remove_by_index(&mut self, index: usize);
    fn as_any_ref(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

impl<T: 'static> Stripe for Vec<T> {
    fn remove_by_index(&mut self, index: usize) {
        self.remove(index);
    }
    fn as_any_ref(&self) -> &dyn Any {
        self
    }
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl Container {
    pub fn new<A: Archetype>() -> Self {
        let mut result = Self {
            components: HashMap::new(),
        };
        A::map(&mut result);
        result
    }

    pub fn push<T: Component>(&mut self, component: T) {
        if let Some(v) = self.components.get_mut(&TypeId::of::<T>()) {
            v.as_any_mut().downcast_mut::<Vec<T>>().unwrap().push(component)
        }
    }

    pub fn init<T: Component>(&mut self) {
        self.components.insert(TypeId::of::<T>(), Box::new(Vec::<T>::new()));
    }

    pub fn get_mut<T: Component>(&self) -> Option<&mut Vec<T>>
    where T: Component
    {
        self.components
            .get(&TypeId::of::<T>())
            .map(|v| {
                unsafe {
                    let vec_ref = v.as_any_ref().downcast_ref::<Vec<T>>().unwrap();
                    let vec_ptr = vec_ref as *const Vec<T>;
                    let mut_ptr = vec_ptr as *mut Vec<T>;
                    &mut *mut_ptr
                }
            })
    }

    pub fn get<T: Component>(&self) -> Option<&Vec<T>>
    where T: Component
    {
        self.components
            .get(&TypeId::of::<T>())
            .map(|v| v.as_any_ref().downcast_ref::<Vec<T>>().unwrap())
    }

    pub fn has(&self, key: TypeId) -> bool {
        self.components.contains_key(&key)
    }

    pub fn len(&self) -> usize {
        self.components.len()
    }

    pub fn remove(&mut self, index: usize) {
        for stripe in self.components.values_mut() {
            stripe.remove_by_index(index);
        }
    }
}

#[cfg(test)]
mod tests {
    struct Item1(u32);
    struct Item2(u32);
    use crate::world::container::Container;
    #[test]
    fn mutability() {
        let mut c = Container::new::<(Item1, Item2)>();
        c.push::<Item1>(Item1(123));
        c.push::<Item2>(Item2(666));

        for i in c.get_mut::<Item1>().unwrap() {
            i.0 += 198;
        }

        for i in c.get::<Item1>().unwrap() {
            assert_eq!(i.0, 321);
        }

    }
}