qecs-core 0.0.13

Soon to be highly flexible Entity-Component-System framework, core lib.
Documentation
use super::primitives::{Id, Valid};

use std::any::Any;

// ++++++++++++++++++++ Id[Generation|Activation]Error ++++++++++++++++++++ 

#[derive(Debug, PartialEq, Eq)]
pub enum IdGenerationError {
    /// The id couldn't be activated because the maximum id count this id-type
    /// or this id-manager allows was reached.
    ///
    /// TODO: naming?
    MaximumIdCountReached(usize),
}

pub type IdGenerationResult<T> = Result<T, IdGenerationError>;

#[derive(Debug, PartialEq, Eq)]
pub enum IdActivationError<Slot> {
    /// The id couldn't be activated because the maximum id count this id-type
    /// or this id-manager allows was reached.
    ///
    /// TODO: naming?
    MaximumIdCountReached(usize),
    
    /// The id couldn't be activated because it already is. 
    AlreadyActivated,
    
    /// The id couldn't be activated because the internal slot (in the id-manager) it 
    /// would use is already occupied.
    /// 
    /// This can be the case for id-types which have an generation attached (`SafeIndex`).
    ///
    /// Example: You try to activate `a = {idx:200, gen:5}`, but `b = {idx:200, gen:4}` 
    /// is already active. If you want to force `a`s activation, you first need to 
    /// invalidate `b`.
    SlotOccupied(Slot),
}

impl<Slot> IdActivationError<Slot> {
    // TODO remove this?
    #[doc(hidden)]
    pub fn from_err<X>(err: IdActivationError<X>) -> Self {
        match err {
            IdActivationError::MaximumIdCountReached(max) => {
                IdActivationError::MaximumIdCountReached(max)
            }
            IdActivationError::AlreadyActivated => {
                IdActivationError::AlreadyActivated
            }
            _ => unreachable!()
        }
    }
}

pub type IdActivationResult<T, Slot> = Result<T, IdActivationError<Slot>>;

pub trait _PrimaryIdManager<'a> {
    type _Id: Id;

    type Iter: Iterator<Item = Valid<'a, Self::_Id>> + 'a;
}

pub trait PrimaryIdManager: Any + Sync + Send 
    where Self: for<'a> _PrimaryIdManager<'a, _Id = <Self as PrimaryIdManager>::Id>
{
    type Id: Id;

    fn len(&self) -> usize;

    fn maximum_id_count(&self) -> usize;

    /// Tests if `id` is usable.
    fn validate(&self, id: Self::Id) -> Option<Valid<Self::Id>>;                 

    /// Makes `id` unusable and returns `true`. 
    /// Returns `false` if `id` is already invalid.
    unsafe fn invalidate(&mut self, id: Self::Id) -> bool;

    /// Generates a new id.
    fn generate(&mut self) -> IdGenerationResult<Valid<Self::Id>>;

    fn activate(&mut self, id: Self::Id) -> IdActivationResult<Valid<Self::Id>, Self::Id>;

    unsafe fn clear(&mut self);

    fn iter<'a>(&'a self) -> <Self as _PrimaryIdManager<'a>>::Iter;
}

/* NOTE: old code
// ++++++++++++++++++++ IdManager-traits ++++++++++++++++++++ 

/// This is just to share some code between `PrimaryIdManager` and `SecondaryIdManager`.
pub trait IdManager: Any + Sync + Send {
    type Id: Id;

    fn len(&self) -> usize;

    fn maximum_id_count(&self) -> usize;
}

/// ...
///
/// If `Self` provides an iterator, its item should be `Valid<'a, Self::Id>`.
pub trait PrimaryIdManager: IdManager{
    /// Tests if `id` is usable.
    fn validate(&self, id: Self::Id) -> Option<Valid<Self::Id>>;

    /// Makes `id` unusable and returns `true`. 
    /// Returns `false` if `id` is already invalid.
    unsafe fn invalidate(&mut self, id: Self::Id) -> bool;

    /// Generates a new id.
    fn generate(&mut self) -> IdGenerationResult<Valid<Self::Id>>;

    fn activate(&mut self, id: Self::Id) -> IdActivationResult<Valid<Self::Id>, Self::Id>;

    /// TODO should this be `Valid<Self::Id>`?
    fn slot_of(&mut self, id: Self::Id) -> Option<Self::Id>;

    unsafe fn clear(&mut self);
}

/// This is just some interface-glue for `Composite[Multi]IdStore`.
/// You most likely won't use this trait directly. 
///
/// If `Self` provides an iterator, it will remain unused (at least by 
/// `Composite[Multi]IdStore`, that is).
pub trait SecondaryIdManager: IdManager{
    type PrimaryId: Id;

    /// Tests if `id` is usable and if so, returns the primary id it was 
    /// activated for.
    fn validate(&self, m_id: Self::Id) -> Option<Valid<Self::PrimaryId>>;

    /// Makes `id` unusable and returns the primary id it was activated for.
    /// Returns `None` if `id` is already invalid.
    ///
    /// The returned primary id is guaranteed to be valid until the borrow is released.
    fn invalidate(&mut self, id: Self::Id) -> Option<Valid<Self::PrimaryId>>;

    /// Generates a new id and activates it for `p_id`.
    ///
    /// Note that this method doesn't check if there's already a managed id activated for
    /// `p_id`. This can be intended behavior, see `CompositeMultiIdStore`.
    fn generate_for<'id>(
        &mut self, 
        p_id: Valid<'id, Self::PrimaryId>
    ) -> IdGenerationResult<Self::Id>;

    /// ...
    ///
    /// Note that this method doesn't check if there's already a managed id activated for
    /// `p_id`. This can be intended behavior, see `CompositeMultiIdStore`.
    fn activate_for<'id>(
        &mut self, 
        p_id: Valid<'id, Self::PrimaryId>,
        m_id: Self::Id,
    ) -> IdActivationResult<(), (Self::Id, Self::PrimaryId)>;

    /// TODO should this return `(Self::Id, Valid<Self::PrimaryId>)`?
    ///
    /// TODO should `id` be `usize`?
    fn slot_of(&mut self, id: Self::Id) -> Option<(Self::Id, Self::PrimaryId)>;

    fn clear(&mut self);
}
*/