pkecs 8.0.0

Another ECS implementation.
Documentation
//! Contains types for interacting with an entity store.

use std::{any::TypeId, collections::HashMap, hash::Hash};
use crate::component::{ComponentChannel, ComponentMap, ErasedComponentChannel};

/// Represents an entity store.
///
/// Contains APIs to spawn and query entities.
#[derive(Default)]
pub struct Entities {
    /// A map of component channels indexed by the type they contain.
    components: HashMap<TypeId, Box<dyn ErasedComponentChannel>>,
}

impl Entities {
    /// Adds a component to [`self`].
    pub fn spawn<T>(&mut self, component: T)
        where
            T: 'static,
    {
        let id = TypeId::of::<T>();

        self.components
            .entry(id)
            .or_insert(ComponentChannel::<T>::new_box())
            .as_any_mut()
            .downcast_mut::<ComponentChannel<T>>()
            .map(|c| c.push(component));
    }

    /// Adds an indexed component to [`self`].
    pub fn spawn_indexed<TKey, TValue>(&mut self, key: TKey, component: TValue)
        where
            TKey: Eq + Hash + 'static,
            TValue: 'static,
    {
        let id = TypeId::of::<(TKey, TValue)>();

        self.components
            .entry(id)
            .or_insert(ComponentMap::<TKey, TValue>::new_box())
            .as_any_mut()
            .downcast_mut::<ComponentMap<TKey, TValue>>()
            .map(|c| c.insert(key, component));
    }

    /// Retrieves an immutable reference to component set.
    pub fn query<'c, T: 'static>(&'c self) -> QueryRef<'c, T> {
        let id = TypeId::of::<T>();

        let channel = self.components
            .get(&id)
            .map(|c| c.as_any())
            .and_then(|c| c.downcast_ref::<ComponentChannel::<T>>());

        QueryRef::<T>::from_channel(channel)
    }

    /// Retrieves a mutable referent to an component set.
    pub fn query_mut<'c, T: 'static>(&'c mut self) -> QueryMut<'c, T> {
        let id = TypeId::of::<T>();

        let channel = self.components
            .get_mut(&id)
            .map(|c| c.as_any_mut())
            .and_then(|c| c.downcast_mut::<ComponentChannel::<T>>());

        QueryMut::<T>::from_channel(channel)
    }

    /// Retrieves multiple mutable component set references.
    pub fn query_disjoint_mut<'c, const N: usize>(&'c mut self, component_ids: [&TypeId; N]) -> QueryDisjointMut<'c> {
        let channels = self.components
            .get_disjoint_mut(component_ids)
            .into_iter()
            .filter_map(|c| c);

        let channel_ids = component_ids
            .into_iter()
            .cloned();

        let channels_map = channel_ids
            .zip(channels)
            .collect::<HashMap<TypeId, &mut Box<dyn ErasedComponentChannel>>>();

        QueryDisjointMut::from_channels(channels_map)
    }

    /// Retrieves an immutable reference to an indexed channel of components.
    pub fn query_indexed<'c, TKey, TValue>(&'c self) -> QueryIndexedRef<'c, TKey, TValue>
        where
            TKey: Eq + Hash + 'static,
            TValue: 'static,
    {
        let id = TypeId::of::<(TKey, TValue)>();

        let channel = self.components
            .get(&id)
            .map(|c| c.as_any())
            .and_then(|c| c.downcast_ref::<ComponentMap<TKey, TValue>>());

        QueryIndexedRef::from_channel(channel)
    }

    /// Retrieves a mutable reference to an indexed channel of components.
    pub fn query_indexed_mut<'c, TKey, TValue>(&'c mut self) -> QueryIndexedMut<'c, TKey, TValue>
        where
            TKey: Eq + Hash + 'static,
            TValue: 'static,
    {
        let id = TypeId::of::<(TKey, TValue)>();

        let channel = self.components
            .get_mut(&id)
            .map(|c| c.as_any_mut())
            .and_then(|c| c.downcast_mut::<ComponentMap<TKey, TValue>>());

        QueryIndexedMut::from_channel(channel)
    }
}

/// An immutable reference to a set of components.
pub struct QueryRef<'c, T> {
    channel: Option<&'c ComponentChannel<T>>
}

impl<'c, T> QueryRef<'c, T> {
    /// Initializes [`self`] from an ummutable reference to [`ComponentPool`].
    const fn from_channel(channel: Option<&'c ComponentChannel<T>>) -> Self {
        Self { channel }
    }

    /// Iterates over a set of components.
    ///
    /// Will return an empty [`Iterator`] if [`self`] is invalid.
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.channel
            .iter()
            .flat_map(|c| c.iter())
    }

    /// Retrieves the first component in the set.
    ///
    /// Will return [`None`] if [`self`] is invalid.
    pub fn first(&self) -> Option<&T> {
        self.iter()
            .next()
    }
}

/// A mutable reference to a set of components.
pub struct QueryMut<'c, T> {
    channel: Option<&'c mut ComponentChannel<T>>,
}

impl<'c, T> QueryMut<'c, T> {
    /// Initializes [`self`] from a mutable reference to [`ComponentChannel`].
    const fn from_channel(channel: Option<&'c mut ComponentChannel<T>>) -> Self {
        Self { channel }
    }

    /// Iterates over a set of components.
    ///
    /// Will return an empty [`Iterator`] if [`self`] is invalid.
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
        self.channel
            .iter_mut()
            .flat_map(|c| c.iter_mut())
    }

    /// Retrieves the first component in [`self`].
    ///
    /// Will return [`None`] if there are no components in the set or if it didn't exist.
    pub fn first_mut(&mut self) -> Option<&mut T> {
        self.iter_mut()
            .next()
    }
}

/// A query into disjoint component channels.
pub struct QueryDisjointMut<'c> {
    channels: HashMap<TypeId, &'c mut Box<dyn ErasedComponentChannel>>,
}

impl<'c> QueryDisjointMut<'c> {
    /// Initializes [`self`] from a map of [`ErasedComponentChannel`].
    const fn from_channels(channels: HashMap<TypeId, &'c mut Box<dyn ErasedComponentChannel>>) -> Self {
        Self { channels }
    }

    /// Iterates over a set of components.
    ///
    /// Returns an empty [`Iterator`] if the component set does not exist.
    pub fn iter_mut<T: 'static>(&mut self) -> impl Iterator<Item = &mut T> {
        let id = TypeId::of::<T>();

        self.channels
            .get_mut(&id)
            .map(|c| c.as_any_mut())
            .and_then(|a| a.downcast_mut::<ComponentChannel<T>>())
            .into_iter()
            .flat_map(|c| c.iter_mut())
    }

    /// Retrieves the first component in the set.
    ///
    /// Returns [`None`] if the component set is empty.
    pub fn first_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.iter_mut()
            .next()
    }
}

/// An immutable query against an indexed component set.
pub struct QueryIndexedRef<'c, TKey, TValue> {
    channel: Option<&'c ComponentMap<TKey, TValue>>,
}

impl<'c, TKey, TValue> QueryIndexedRef<'c, TKey, TValue>
    where
        TKey: Eq + Hash,
{
    /// Initializes [`self`] from an immutable reference to [`ComponentMap`].
    pub const fn from_channel(channel: Option<&'c ComponentMap<TKey, TValue>>) -> Self {
        Self { channel }
    }

    /// Gets an immutable reference to a component via it's key.
    pub fn get(&self, key: &TKey) -> Option<&'c TValue> {
        self.channel.and_then(|c| c.get(key))
    }

    /// Returns an [`Iterator`] over each key-value pair in the component channel.
    pub fn iter(&self) -> impl Iterator<Item = (&'c TKey, &'c TValue)> {
        self.channel
            .iter()
            .flat_map(|c| c.iter())
    }
}

/// A mutable query against an indexed component set.
pub struct QueryIndexedMut<'c, TKey, TValue> {
    channel: Option<&'c mut ComponentMap<TKey, TValue>>,
}

impl<'c, TKey, TValue> QueryIndexedMut<'c, TKey, TValue>
    where
        TKey: Eq + Hash,
{
    /// Initializes [`self`] from an immutable reference to [`ComponentMap`].
    pub const fn from_channel(channel: Option<&'c mut ComponentMap<TKey, TValue>>) -> Self {
        Self { channel }
    }

    /// Gets an immutable reference to a component via it's key.
    pub fn get_mut(&'c mut self, key: &TKey) -> Option<&'c mut TValue> {
        self.channel
            .as_mut()
            .and_then(|c| c.get_mut(key))
    }

    /// Returns an [`Iterator`] over all key-value pairs in the component channel.
    pub fn iter_mut(&'c mut self) -> impl Iterator<Item = (&'c TKey, &'c mut TValue)> {
        self.channel
            .iter_mut()
            .flat_map(|c| c.iter_mut())
    }
}