checs 0.5.1

An Entity-Component-System library.
Documentation
//! Managing entities and their components.

use crate::component::ComponentVec;
use crate::entity;

/// A container for managing entities and their components.
///
/// # Examples
///
/// ```
/// use checs::{ComponentVec, IntoQuery, LendingIterator, Storage, World};
///
/// #[derive(Default, Storage)]
/// struct Storage {
///     strs: ComponentVec<&'static str>,
///     ints: ComponentVec<i32>,
/// }
///
/// let mut world = World::<Storage>::new();
///
/// let e0 = world.spawn_with(("ninety-nine", 99));
/// let e1 = world.spawn_with(("zero",));
/// let e2 = world.spawn_with(("forty-two", 42));
/// let e3 = world.spawn_with((1,));
/// let e4 = world.spawn_with(("seventeen", 17));
///
/// let storage = world.storage_mut();
/// let mut query = (&storage.strs, &mut storage.ints).into_query();
///
/// assert_eq!(query.next(), Some((e0, (&"ninety-nine", &mut 99))));
/// assert_eq!(query.next(), Some((e2, (&"forty-two", &mut 42))));
/// assert_eq!(query.next(), Some((e4, (&"seventeen", &mut 17))));
/// assert_eq!(query.next(), None);
/// ```
pub struct World<S> {
    storage: S,
    entity_allocator: entity::Allocator,
}

impl<S> World<S> {
    /// Constructs a new `World`.
    #[must_use]
    #[inline]
    pub fn new() -> Self
    where
        S: Default,
    {
        World {
            entity_allocator: entity::Allocator::new(),
            storage: S::default(),
        }
    }

    /// Returns a reference to the component storage.
    #[must_use]
    #[inline]
    pub fn storage(&self) -> &S {
        &self.storage
    }

    /// Returns a mutable reference to the component storage.
    #[must_use]
    #[inline]
    pub fn storage_mut(&mut self) -> &mut S {
        &mut self.storage
    }

    /// Creates a new entity.
    #[must_use]
    #[inline]
    pub fn spawn(&mut self) -> entity::Entity {
        self.entity_allocator.alloc()
    }

    /// Creates a new entity with initial components.
    #[inline]
    pub fn spawn_with<T>(&mut self, value: T) -> entity::Entity
    where
        Self: InsertMany<T>,
    {
        let entity = self.entity_allocator.alloc();

        _ = self.insert_many(entity, value);

        entity
    }

    /// Removes an `entity` and its components.
    ///
    /// # Errors
    ///
    /// The method internally calls [`entity::Allocator::free`], so it might return any of its
    /// errors.
    #[inline]
    pub fn despawn(&mut self, entity: entity::Entity) -> Result<(), entity::Error>
    where
        S: RemoveAll,
    {
        self.storage.remove_all(entity);
        self.entity_allocator.free(entity)
    }

    /// Removes all entities that have the specified component `T`.
    ///
    /// Also removes all of their other components.
    ///
    /// # Errors
    ///
    /// The method internally calls [`entity::Allocator::free`], so it might return any of its
    /// errors.
    #[inline]
    pub fn despawn_all<T>(&mut self) -> Result<(), entity::Error>
    where
        S: RemoveAll + AsRef<ComponentVec<T>>,
    {
        while let Some((e, _)) = self.storage.as_ref().iter().next() {
            self.despawn(e)?;
        }

        Ok(())
    }

    /// Removes all `entities` in the iterator from the world.
    ///
    /// Also removes all of their components.
    ///
    /// # Errors
    ///
    /// The method internally calls [`entity::Allocator::free`], so it might return any of its
    /// errors.
    #[inline]
    pub fn despawn_entities<'a, I>(&'a mut self, entities: I) -> Result<(), entity::Error>
    where
        S: RemoveAll,
        I: IntoIterator<Item = &'a entity::Entity>,
    {
        for &entity in entities {
            self.despawn(entity)?;
        }

        Ok(())
    }

    /// Returns a reference to the `entity`'s component, or `None` if the entity does not have that
    /// component.
    #[must_use]
    #[inline]
    pub fn get<T>(&self, entity: entity::Entity) -> Option<&T>
    where
        S: AsRef<ComponentVec<T>>,
    {
        self.storage.as_ref().get(entity)
    }

    /// Returns a mutable reference to an `entity`'s component, or `None` if the `entity` does not
    /// have that component.
    #[must_use]
    #[inline]
    pub fn get_mut<T>(&mut self, entity: entity::Entity) -> Option<&mut T>
    where
        S: AsMut<ComponentVec<T>>,
    {
        self.storage.as_mut().get_mut(entity)
    }

    /// Adds a component to the `entity`.
    ///
    /// If the `entity` already had that component its value is updated and the old value is
    /// returned.
    #[inline]
    pub fn insert<T>(&mut self, entity: entity::Entity, value: T) -> Option<T>
    where
        S: AsMut<ComponentVec<T>>,
    {
        self.storage.as_mut().insert(entity, value)
    }

    /// Removes a component from the `entity` and returns the component.
    #[inline]
    pub fn remove<T>(&mut self, entity: entity::Entity) -> Option<T>
    where
        S: AsMut<ComponentVec<T>>,
    {
        self.storage.as_mut().remove(entity)
    }
}

impl<S> Default for World<S>
where
    S: Default,
{
    #[inline]
    fn default() -> World<S> {
        World::new()
    }
}

/// A trait for removing all components from an `entity`.
///
/// # Note
///
/// This trait is not meant to be used or implemented directly. Instead it is implemented by the
/// custom derive macro [`Storage`], which is why it must be public.
///
/// [`Storage`]: crate::Storage
pub trait RemoveAll {
    /// Removes all components from an `entity`.
    fn remove_all(&mut self, entity: entity::Entity);
}

/// A trait for adding multiple components to an `entity`.
///
/// # Note
///
/// This trait is not meant to be used or implemented directly. Instead it is implemented by the
/// custom derive macro [`Storage`], which is why it must be public.
///
/// [`Storage`]: crate::Storage
pub trait InsertMany<T> {
    /// The type of the (possibly) updated components.
    type Output;

    /// Adds components to the `entity`.
    ///
    /// If the `entity` already had some components their values are updated and the old values are
    /// returned.
    fn insert_many(&mut self, entity: entity::Entity, value: T) -> Self::Output;
}

impl<S> InsertMany<()> for World<S> {
    type Output = ();

    #[inline]
    fn insert_many(&mut self, _entity: entity::Entity, _value: ()) -> Self::Output {}
}

macro_rules! impl_insert_many {
    ($($T:ident),*) => {
        impl<S, $($T),*> InsertMany<($($T),*,)> for World<S>
        where
            $(
                S: AsMut<$crate::ComponentVec<$T>>,
            )*
        {
            type Output = ($(Option<$T>,)*);

            #[inline]
            fn insert_many(&mut self, entity: entity::Entity, value: ($($T),*,)) -> Self::Output {
                #![allow(non_snake_case)]
                let ($($T),*,) = value;

                ($(
                    self.insert(entity, $T),
                )*)
            }
        }
    };
}

macro_rules! expand {
    ($macro:ident, $head:ident) => {
        $macro!{$head}
    };

    ($macro:ident, $head:ident, $($tail:ident),*) => {
        $macro!{$head, $($tail),*}
        expand!{$macro, $($tail),*}
    };
}

expand!(impl_insert_many, A, B, C, D, E, F, G);

/// Creates a new entity with initial components.
#[macro_export]
macro_rules! spawn {
    ($world:ident, $($component:expr),* $(,)?) => {{
        let entity = $world.spawn();

        $(
            $world.insert(entity, $component);
        )*

        entity
    }};
}

/// Prepares a struct for use as the type parameter of [`World`].
///
/// The struct's fields must be of type [`ComponentVec`]. It implements [`RemoveAll`], as well as
/// [`AsRef`] and [`AsMut`] for each field.
///
/// This macro can be used as an alternative to the custom derive [`Storage`], e.g. because the
/// feature `proc` is not enabled.
///
/// [`Storage`]: crate::Storage
#[macro_export]
macro_rules! derive_storage {
    ($( $tokens:tt )*) => {
        $( $tokens )*
        $crate::internal_derive_storage! { $( $tokens )* }
    };
}

/// <div class="warning">
///
/// This is for internal use only! If you find yourself using it, consider using the custom derive
/// [`checs_proc::Storage`] instead.
///
/// </div>
#[macro_export]
#[doc(hidden)]
macro_rules! internal_derive_storage {
    (
        $( #[$_meta:meta] )*
        $_vis:vis struct $name:ident {
            $(
                $( #[$_meta_field:meta] )*
                $_vis_field:vis $field:ident : $type:ty,
            )*
        }
    ) => {
        impl $crate::world::RemoveAll for $name {
            #[inline]
            fn remove_all(&mut self, entity: $crate::entity::Entity) {
                $(
                    self.$field.remove(entity);
                )*
            }
        }

        $(
            impl AsRef<$type> for $name {
                #[inline]
                fn as_ref(&self) -> &$type {
                    &self.$field
                }
            }

            impl AsMut<$type> for $name {
                #[inline]
                fn as_mut(&mut self) -> &mut $type {
                    &mut self.$field
                }
            }
        )*
    };
}