bbecs 0.3.0

ECS library for Brooks Builds projects made live on Twitch at https://twitch.tv/brookzerker.
Documentation
use std::cell::RefCell;
use std::collections::{BTreeMap, HashMap};
use std::rc::Rc;

use eyre::Result;
use ggez::event::KeyCode;
use ggez::graphics::{Color, Mesh, Text, TextFragment};

use crate::errors::BbEcsError;
use crate::{components::ComponentData, data_types::point::Point};

pub trait EntityDataTraits<T> {
    fn insert(&mut self, name: &str, data: T) -> Result<()>;
}

#[derive(Debug, Default)]
pub struct EntityData {
    pub components: HashMap<String, Vec<ComponentData>>,
}

impl EntityData {
    pub fn new() -> Self {
        Self {
            components: HashMap::new(),
        }
    }

    pub fn register(&mut self, name: String) -> Result<()> {
        if self.components.contains_key(&name) {
            return Err(BbEcsError::ComponentAlreadyRegistered(name).into());
        }
        let components = vec![];
        self.components.insert(name, components);
        Ok(())
    }

    pub fn query(
        &self,
        bitmap: BTreeMap<String, &Vec<bool>>,
    ) -> Result<HashMap<String, Vec<&ComponentData>>> {
        let mut results = HashMap::new();

        for (name, map) in bitmap.iter() {
            if let Some(components_list) = self.components.get(name) {
                let mut missing_components_count = 0;
                let mut component_results = vec![];
                for (index, component_map) in map.iter().enumerate() {
                    if *component_map {
                        if self.does_entity_have_all_components(&bitmap, index) {
                            component_results
                                .push(&components_list[index - missing_components_count]);
                        }
                    } else {
                        missing_components_count += 1;
                    }
                }
                results.insert(name.to_owned(), component_results);
            } else {
                return Err(BbEcsError::ComponentNotFound(name.to_owned()).into());
            }
        }

        Ok(results)
    }

    fn does_entity_have_all_components(
        &self,
        bitmap: &BTreeMap<String, &Vec<bool>>,
        entity_index: usize,
    ) -> bool {
        for components in bitmap.values() {
            if !components[entity_index] {
                return false;
            }
        }

        true
    }

    pub fn delete_entities_by_index(&mut self, bitmap: HashMap<String, Vec<usize>>) -> Result<()> {
        for (component_name, mut indexes_to_delete) in bitmap {
            indexes_to_delete.reverse();
            if let Some(components) = self.components.get_mut(&component_name) {
                for index in indexes_to_delete {
                    components.remove(index);
                }
            }
        }

        Ok(())
    }
}

impl EntityDataTraits<Point> for EntityData {
    fn insert(&mut self, name: &str, data: Point) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Point(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<Color> for EntityData {
    fn insert(&mut self, name: &str, data: Color) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Color(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<f32> for EntityData {
    fn insert(&mut self, name: &str, data: f32) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::F32(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<Mesh> for EntityData {
    fn insert(&mut self, name: &str, data: Mesh) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Mesh(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<u32> for EntityData {
    fn insert(&mut self, name: &str, data: u32) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::U32(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<usize> for EntityData {
    fn insert(&mut self, name: &str, data: usize) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Usize(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<bool> for EntityData {
    fn insert(&mut self, name: &str, data: bool) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Bool(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<KeyCode> for EntityData {
    fn insert(&mut self, name: &str, data: KeyCode) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::GgezKeyCode(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<String> for EntityData {
    fn insert(&mut self, name: &str, data: String) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::Marker(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<Text> for EntityData {
    fn insert(&mut self, name: &str, data: Text) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::GgezText(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<ggez::audio::SoundData> for EntityData {
    fn insert(&mut self, name: &str, data: ggez::audio::SoundData) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::GgezSound(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}

impl EntityDataTraits<TextFragment> for EntityData {
    fn insert(&mut self, name: &str, data: TextFragment) -> Result<()> {
        if let Some(components) = self.components.get_mut(name) {
            components.push(ComponentData::GgezTextFragment(Rc::new(RefCell::new(data))));
        } else {
            return Err(BbEcsError::NeedToRegister.into());
        }
        Ok(())
    }
}