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 }
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 {}
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
{
self.untyped.fmt(f)
}
}