ecs-tiny 0.4.0

A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
Documentation
//! # ecs-tiny
//! 
//! A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
//!
//! # Usages
//! 
//! ```
//! // Define an component:
//!
//! #[repr(C)]
//! #[derive(Debug, Clone, Copy, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
//! pub struct ComponentA(i32);
//! impl ecs_tiny::Component for ComponentA {}
//!
//! // Create new ecs instance and inserts new entity:
//!
//! let mut world = ecs_tiny::World::new();
//! 
//! let entity_key0 = world.insert_entity();
//! let entity_key1 = world.insert_entity();
//!
//! // Inserts new component associated with specified entity:
//! 
//! assert_eq!(world.insert_component(entity_key0, ComponentA(42)), Some(()));
//! assert_eq!(world.insert_component(entity_key1, ComponentA(63)), Some(()));
//! 
//! // Iterates over all components of specified type (single type only):
//! 
//! for ComponentA(value) in world.iter_component_mut::<ComponentA>() {
//!     *value += 1;
//! }
//! 
//! // Removes specified component:
//! 
//! world.remove_component::<ComponentA>(entity_key0).unwrap();
//! 
//! // Removes specified entity:
//! 
//! world.remove_entity(entity_key1).unwrap();
//! ```

mod util;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EntityKey(usize);

pub trait Component: bytemuck::Pod {}

#[derive(Debug)]
struct ComponentColumn {
    sparse: util::SparseIndex<256>,
    dense: util::BlobStorage,
    rev: Vec<usize>,
}

impl ComponentColumn {
    #[inline]
    fn new<T>() -> Self where T: Component {
        Self {
            sparse: Default::default(),
            dense: util::BlobStorage::new::<T>(),
            rev: Default::default(),
        }
    }

    fn insert<T>(&mut self, entity_key: usize, comp: T) -> Option<T> where T: Component {
        if let Some(index) = self.sparse.get(entity_key) {
            let target = self.dense.get_mut::<T>(*index).unwrap();
            let old = std::mem::replace(target, comp);
            return Some(old);
        }

        let index = self.dense.len();
        self.dense.push(comp);
        self.rev.push(entity_key);
        self.sparse.insert(entity_key, index);
        None
    }

    fn remove(&mut self, entity_key: usize) -> Option<()> {
        let index = self.sparse.remove(entity_key)?;
        self.dense.swap_remove(index);
        self.rev.swap_remove(index);

        if let Some(entity_key) = self.rev.get(index) {
            let target = self.sparse.get_mut(*entity_key).unwrap();
            *target = index;
        }
        Some(())
    }

    #[inline]
    fn get<T>(&self, entity_key: usize) -> Option<&T> where T: Component {
        let index = *self.sparse.get(entity_key)?;
        let component = self.dense.get(index).unwrap();
        Some(component)
    }

    #[inline]
    fn get_mut<T>(&mut self, entity_key: usize) -> Option<&mut T> where T: Component {
        let index = *self.sparse.get(entity_key)?;
        let component = self.dense.get_mut(index).unwrap();
        Some(component)
    }

    #[inline]
    fn iter<T>(&self) -> impl Iterator<Item = &T> where T: Component {
        self.dense.iter()
    }

    #[inline]
    fn iter_mut<T>(&mut self) -> impl Iterator<Item = &mut T> where T: Component {
        self.dense.iter_mut()
    }
}

/// A minimal ECS supporting entity and component insertion/removal, association, and single-type iteration.
#[derive(Debug, Default)]
pub struct World {
    entities: slab::Slab<()>,
    component_table: util::IndexMap<std::any::TypeId, ComponentColumn>,
}

impl World {
    /// Create a new ECS instance.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Insert a new entity and return the corresponding entity key.
    pub fn insert_entity(&mut self) -> EntityKey {
        let entity_key = self.entities.insert(());
        EntityKey(entity_key)
    }

    /// Remove an entity with the corresponding entity key.
    /// If the entity corresponding to the entity key is not found, return an `None`.
    /// Otherwise, return an `Some(())`.
    pub fn remove_entity(&mut self, entity_key: EntityKey) -> Option<()> {
        let EntityKey(entity_key) = entity_key;
        self.entities.try_remove(entity_key)?;

        for component_column in self.component_table.iter_mut() {
            component_column.remove(entity_key);
        }

        Some(())
    }

    /// Return entity with the corresponding entity key.
    /// If the entity corresponding to the entity key is not found, return an `None`.
    /// Otherwise, return an `Some(())`.
    #[inline]
    pub fn contains_entity(&self, entity_key: EntityKey) -> bool {
        let EntityKey(entity_key) = entity_key;
        self.entities.get(entity_key).is_some()
    }

    /// Return an iterator over all entity keys.
    #[inline]
    pub fn iter_entity(&self) -> impl Iterator<Item = EntityKey> + '_ {
        self.entities.iter().map(|(entity_key, _)| EntityKey(entity_key))
    }

    /// Insert a new component with the corresponding entity key and return the corresponding component key.
    /// If the entity corresponding to the entity key is not found, return an `None`.
    /// Otherwise, return an `Some(CompKey)`.
    pub fn insert_component<T>(&mut self, entity_key: EntityKey, component: T) -> Option<()> where T: Component {
        let EntityKey(entity_key) = entity_key;
        self.entities.get(entity_key)?;

        let type_key = std::any::TypeId::of::<T>();
        if !self.component_table.contains_key(&type_key) {
            self.component_table.insert(type_key, ComponentColumn::new::<T>());
        }
        let component_column = self.component_table.get_mut(&type_key).unwrap();
        component_column.insert(entity_key, component);
        Some(())
    }

    /// Remove a component with the corresponding component key and type, and return the component.
    /// If the component corresponding to the component key and type is not found, return an `None`.
    /// Otherwise, return an `Some(())`.
    pub fn remove_component<T>(&mut self, entity_key: EntityKey) -> Option<()> where T: Component {
        let EntityKey(entity_key) = entity_key;
        self.entities.get(entity_key)?;

        let type_key = std::any::TypeId::of::<T>();
        let component_column = self.component_table.get_mut(&type_key)?;
        component_column.remove(entity_key)?;
        Some(())
    }

    /// Return a component with the corresponding component key and type.
    /// If the component corresponding to the component key and type is not found, return an `None`.
    /// Otherwise, return an `Some(&T)`.
    #[inline]
    pub fn get_component<T>(&self, entity_key: EntityKey) -> Option<&T> where T: Component {
        let EntityKey(entity_key) = entity_key;
        self.entities.get(entity_key)?;

        let type_key = std::any::TypeId::of::<T>();
        let component_column = self.component_table.get(&type_key)?;
        let component = component_column.get(entity_key)?;
        Some(component)
    }

    /// Return a mutable component with the corresponding component key and type.
    /// If the component corresponding to the component key and type is not found, return an `None`.
    /// Otherwise, return an `Some(&mut T)`.
    #[inline]
    pub fn get_component_mut<T>(&mut self, entity_key: EntityKey) -> Option<&mut T> where T: Component {
        let EntityKey(entity_key) = entity_key;
        self.entities.get(entity_key)?;

        let type_key = std::any::TypeId::of::<T>();
        let component_column = self.component_table.get_mut(&type_key)?;
        let component = component_column.get_mut(entity_key)?;
        Some(component)
    }

    /// Return an iterator over all components of the corresponding type.
    /// If the component type is not found, return an `None`.
    /// Otherwise, return an `Some(impl Iterator<Item = &T>)`.
    #[inline]
    pub fn iter_component<T>(&self) -> impl Iterator<Item = &T> where T: Component {
        let type_key = std::any::TypeId::of::<T>();
        if let Some(component_column) = self.component_table.get(&type_key) {
            return either::Left(component_column.iter());
        }
        either::Right(std::iter::empty())
    }

    /// Return a mutable iterator over all components of the corresponding type.
    /// If the component type is not found, return an `None`.
    /// Otherwise, return an `Some(impl Iterator<Item = &mut T>)`.
    #[inline]
    pub fn iter_component_mut<T>(&mut self) -> impl Iterator<Item = &mut T> where T: Component {
        let type_key = std::any::TypeId::of::<T>();
        if let Some(component_column) = self.component_table.get_mut(&type_key) {
            return either::Left(component_column.iter_mut());
        }
        either::Right(std::iter::empty())
    }
}