hexga_generational 0.0.11-beta.56

GenVec, ideal for MAS (Multi-Agent System), where each agent can be removed at any time and has references to other agents.
use super::*;

pub mod prelude
{
    pub use super::GenID;
    pub use super::traits::*;
    pub(crate) use super::{GenIDOf, Generation, UntypedGenIDOf};
}

pub mod traits
{
    pub use super::{GenerationalID, GenerationalIndex};
}

pub trait GenerationalID<Gen = Generation>:
    From<(usize, Gen)> + Into<(usize, Gen)> + Clone + Copy + PartialEq + Eq + Hash + Ord + PartialOrd + Default
where
    Gen: GenerationalIndex,
{
    fn from_index_and_generation(index: usize, generation: Gen) -> Self { Self::from((index, generation)) }

    fn index(self) -> usize;
    fn generation(self) -> Gen;
    #[inline(always)]
    fn index_and_generation(self) -> (usize, Gen) { (self.index(), self.generation()) }

    fn is_null(self) -> bool { self == Self::NULL }
    fn is_not_null(self) -> bool { self != Self::NULL }

    /// Set the value to `Self::NULL`
    fn reset(&mut self) { *self = Self::NULL; }

    const NULL: Self;

    #[inline(always)]
    fn typed<T>(self) -> GenIDOf<T, Gen> { GenIDOf::from(self.index_and_generation()) }
    #[inline(always)]
    fn untyped(self) -> UntypedGenIDOf<Gen> { UntypedGenIDOf::from(self.index_and_generation()) }
}

pub trait GenerationalIndex: Eq + Hash + Ord + Increment + Decrement + OverflowBehavior + Debug + MaxValue + MinValue + Zero + Copy + 'static {}
impl<T> GenerationalIndex for T where T: Eq + Hash + Ord + Increment + Decrement + OverflowBehavior + Debug + MaxValue + MinValue + Zero + Copy + 'static {}

// Todo: Make a flag for the generation
pub type Generation = u32;
pub type GenID<T> = GenIDOf<T, Generation>;
pub type UntypedGenID = UntypedGenIDOf<Generation>;

pub(crate) struct GenerationDebug<T>(pub(crate) T);
impl<T> Debug for GenerationDebug<T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "#{:?}", self.0) }
}

#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct UntypedGenIDOf<Gen: GenerationalIndex = Generation>
{
    index: usize,
    generation: Gen,
}
impl<Gen: GenerationalIndex> Default for UntypedGenIDOf<Gen>
{
    fn default() -> Self { Self::NULL }
}
impl<Gen: GenerationalIndex> GenerationalID<Gen> for UntypedGenIDOf<Gen>
{
    fn index(self) -> usize { self.index }
    fn generation(self) -> Gen { self.generation }

    const NULL: Self = Self {
        index: usize::MAX,
        generation: Gen::MIN,
    };
}
impl<Gen: GenerationalIndex> UntypedGenIDOf<Gen>
{
    #[inline(always)]
    pub const fn from_index_and_generation(index: usize, generation: Gen) -> Self { Self { index, generation } }

    #[inline(always)]
    pub const fn index(self) -> usize { self.index }
    #[inline(always)]
    pub const fn generation(self) -> Gen { self.generation }
}
impl<Gen: GenerationalIndex, C> IndexExtension<C> for UntypedGenIDOf<Gen> {}

impl<Gen: GenerationalIndex> From<(usize, Gen)> for UntypedGenIDOf<Gen>
{
    fn from((index, generation): (usize, Gen)) -> Self { Self::from_index_and_generation(index, generation) }
}
impl<Gen: GenerationalIndex> From<UntypedGenIDOf<Gen>> for (usize, Gen)
{
    fn from(value: UntypedGenIDOf<Gen>) -> Self { (value.index, value.generation) }
}
impl<T, Gen: GenerationalIndex> From<GenIDOf<T, Gen>> for UntypedGenIDOf<Gen>
{
    fn from(value: GenIDOf<T, Gen>) -> Self { Self::from_index_and_generation(value.index(), value.generation()) }
}
impl<T, Gen: GenerationalIndex> From<UntypedGenIDOf<Gen>> for GenIDOf<T, Gen>
{
    fn from(value: UntypedGenIDOf<Gen>) -> Self { Self::from_index_and_generation(value.index, value.generation) }
}

#[cfg(feature = "serde")]
impl<Gen: GenerationalIndex> Serialize for UntypedGenIDOf<Gen>
where
    Gen: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if self.index.is_max() { None } else { Some((self.index, self.generation)) }.serialize(serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de, Gen: GenerationalIndex> Deserialize<'de> for UntypedGenIDOf<Gen>
where
    Gen: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        match Option::deserialize(deserializer)?
        {
            Some((index, generation)) => Ok(Self::from_index_and_generation(index, generation)),
            None => Ok(Self::from_index_and_generation(usize::MAX, Gen::MIN)),
        }
    }
}
impl<Gen: GenerationalIndex> Debug for UntypedGenIDOf<Gen>
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        if self.is_null()
        {
            write!(f, "NULL")
        }
        else
        {
            f.debug_tuple("").field(&self.index()).field(&GenerationDebug(self.generation())).finish()
        }
    }
}

pub struct GenIDOf<T, Gen: GenerationalIndex = Generation>
{
    untyped: UntypedGenIDOf<Gen>,
    phantom: PhantomData<T>,
}
impl<T, Gen: GenerationalIndex> Clone for GenIDOf<T, Gen>
{
    fn clone(&self) -> Self
    {
        Self {
            untyped: self.untyped.clone(),
            phantom: PhantomData,
        }
    }
}
impl<T, Gen: GenerationalIndex> Copy for GenIDOf<T, Gen> {}
impl<T, Gen: GenerationalIndex> PartialEq for GenIDOf<T, Gen>
{
    fn eq(&self, other: &Self) -> bool { self.untyped == other.untyped }
}
impl<T, Gen: GenerationalIndex> Eq for GenIDOf<T, Gen> {}
impl<T, Gen: GenerationalIndex> Ord for GenIDOf<T, Gen>
{
    fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.untyped.cmp(&other.untyped) }
}
impl<T, Gen: GenerationalIndex> PartialOrd for GenIDOf<T, Gen>
{
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { self.untyped.partial_cmp(&other.untyped) }
}
impl<T, Gen: GenerationalIndex> Hash for GenIDOf<T, Gen>
{
    fn hash<H: Hasher>(&self, state: &mut H) { self.untyped.hash(state); }
}
impl<T, Gen: GenerationalIndex> Default for GenIDOf<T, Gen>
{
    fn default() -> Self { Self::NULL }
}
impl<T, Gen: GenerationalIndex> GenerationalID<Gen> for GenIDOf<T, Gen>
{
    #[inline(always)]
    fn index(self) -> usize { self.untyped.index() }
    #[inline(always)]
    fn generation(self) -> Gen { self.untyped.generation() }

    const NULL: Self = Self {
        untyped: UntypedGenIDOf::<Gen>::NULL,
        phantom: PhantomData,
    };
}
impl<T, Gen: GenerationalIndex> GenIDOf<T, Gen>
{
    #[inline(always)]
    pub const fn from_index_and_generation(index: usize, generation: Gen) -> Self
    {
        Self {
            untyped: UntypedGenIDOf::<Gen>::from_index_and_generation(index, generation),
            phantom: PhantomData,
        }
    }
    #[inline(always)]

    pub const fn index(self) -> usize { self.untyped.index() }
    #[inline(always)]
    pub const fn generation(self) -> Gen { self.untyped.generation() }
}
impl<T, Gen: GenerationalIndex, C> IndexExtension<C> for GenIDOf<T, Gen> {}

impl<T, Gen: GenerationalIndex> From<(usize, Gen)> for GenIDOf<T, Gen>
{
    fn from((index, generation): (usize, Gen)) -> Self { Self::from_index_and_generation(index, generation) }
}
impl<T, Gen: GenerationalIndex> From<GenIDOf<T, Gen>> for (usize, Gen)
{
    fn from(value: GenIDOf<T, Gen>) -> Self { (value.index(), value.generation()) }
}

#[cfg(feature = "serde")]
impl<T, Gen: GenerationalIndex> Serialize for GenIDOf<T, Gen>
where
    Gen: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.untyped.serialize(serializer)
    }
}

#[cfg(feature = "serde")]
impl<'de, T, Gen: GenerationalIndex> Deserialize<'de> for GenIDOf<T, Gen>
where
    Gen: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Ok(Self::from(UntypedGenIDOf::deserialize(deserializer)?))
    }
}
impl<T, Gen: GenerationalIndex> Debug for GenIDOf<T, Gen>
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        // Todo: use a custom format with the TypeId<T> ?
        self.untyped.fmt(f)
    }
}