use std::num::{NonZeroU16, NonZeroU64};
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GenIndex(pub NonZeroU64);
impl From<NonZeroU64> for GenIndex {
fn from(value: NonZeroU64) -> Self {
GenIndex(value)
}
}
impl From<GenIndex> for NonZeroU64 {
fn from(value: GenIndex) -> Self {
value.0
}
}
impl From<GenIndex> for u64 {
fn from(value: GenIndex) -> Self {
value.0.get()
}
}
impl GenIndex {
#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))]
compile_error!("MTB::Entity only supports 32-bit and 64-bit platform.");
pub const GEN_SHIFT: u32 = 0;
pub const GEN_MASK: u64 = 0xFFFF;
pub const GEN_1: NonZeroU16 = NonZeroU16::new(1).unwrap();
pub const INDEX_MASK: u64 = !Self::GEN_MASK;
pub const INDEX_SHIFT: u32 = Self::GEN_SHIFT + 16;
#[cfg(target_pointer_width = "32")]
pub const INVALID_INDEX: usize = usize::MAX;
#[cfg(target_pointer_width = "64")]
pub const INVALID_INDEX: usize = 0xFFFF_FFFF_FFFF;
pub(crate) const fn do_generation_inc(gene: NonZeroU16) -> NonZeroU16 {
let gene = gene.get();
let gene = match gene.wrapping_add(1) {
0 => 1, other => other,
};
NonZeroU16::new(gene).expect("Generation must be non-zero")
}
pub const fn compose(real_index: usize, generation: NonZeroU16) -> Self {
let real_index = real_index as u64;
let generation = generation.get() as u64;
let value = real_index << Self::INDEX_SHIFT | generation;
let value = NonZeroU64::new(value).expect("GenIndex value must be non-zero");
GenIndex(value)
}
pub const fn generation(self) -> NonZeroU16 {
let gene = (self.0.get() & Self::GEN_MASK) as u16;
NonZeroU16::new(gene).expect("GenIndex generation must be non-zero")
}
pub const fn real_index(self) -> usize {
((self.0.get() & Self::INDEX_MASK) >> Self::INDEX_SHIFT) as usize
}
pub const fn tear(self) -> (usize, NonZeroU16) {
(self.real_index(), self.generation())
}
pub const fn generation_inc(self) -> Self {
let (real_index, generation) = self.tear();
let new_generation = Self::do_generation_inc(generation);
Self::compose(real_index, new_generation)
}
pub const fn generation_match(self, other: Self) -> bool {
let lgene = self.0.get() & Self::GEN_MASK;
let rgene = other.0.get() & Self::GEN_MASK;
lgene == rgene
}
pub const fn replace_index(self, new_index: usize) -> Self {
Self::compose(new_index, self.generation())
}
pub const fn is_invalid(self) -> bool {
self.real_index() == Self::INVALID_INDEX
}
pub const fn to_invalid(self) -> Self {
self.replace_index(Self::INVALID_INDEX)
}
pub const fn new_basic_invalid() -> Self {
GenIndex::compose(Self::INVALID_INDEX, Self::GEN_1)
}
}