use core::{marker::PhantomData, num::NonZeroU32};
use crate::generation::Generation;
#[derive(Clone, Copy, PartialOrd, Ord)]
pub struct Key<T: Copy = ()> {
pub(crate) slot: u32,
pub(crate) generation: Generation,
pub(crate) _key_type: PhantomData<T>,
}
impl<T: Copy> Key<T> {
pub const DANGLING: Self = Self {
slot: u32::MAX,
generation: Generation::DANGLING,
_key_type: PhantomData,
};
pub(crate) const fn new(slot: u32, generation: Generation) -> Self {
Self {
slot,
generation,
_key_type: PhantomData,
}
}
pub const fn from_slot_and_generation(slot: u32, generation: NonZeroU32) -> Self {
Self {
slot,
generation: Generation::from_non_zero_u32(generation),
_key_type: PhantomData,
}
}
#[allow(clippy::arithmetic_side_effects)]
pub const fn to_bits(self) -> u64 {
((self.generation.to_non_zero_u32().get() as u64) << 32) | (self.slot as u64)
}
#[allow(clippy::arithmetic_side_effects)]
pub const fn from_bits(bits: u64) -> Option<Self> {
let generation = (bits >> 32) as u32;
let generation = match Generation::from_u32(generation) {
Some(v) => v,
None => return None,
};
let slot = bits as u32;
Some(Self {
generation,
slot,
_key_type: PhantomData,
})
}
pub const fn generation(&self) -> NonZeroU32 {
self.generation.to_non_zero_u32()
}
pub const fn slot(&self) -> u32 {
self.slot
}
}
impl<T: Copy> core::hash::Hash for Key<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.slot.hash(state);
self.generation.hash(state);
}
}
impl<T: Copy> core::fmt::Debug for Key<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"Key(s {}, g {})",
&self.slot,
&self.generation.to_non_zero_u32().get()
)
}
}
impl<T: Copy> PartialEq for Key<T> {
fn eq(&self, other: &Self) -> bool {
self.slot == other.slot && self.generation == other.generation
}
}
impl<T: Copy> Eq for Key<T> {}
#[cfg(test)]
mod test {
use core::mem::size_of;
use crate::Key;
#[test]
fn size_of_key() {
#[derive(Copy, Clone)]
struct CustomKeyType;
assert_eq!(size_of::<Key<()>>(), 8);
assert_eq!(size_of::<Option<Key<()>>>(), 8);
assert_eq!(size_of::<Key<CustomKeyType>>(), 8);
assert_eq!(size_of::<Option<Key<CustomKeyType>>>(), 8);
}
#[test]
fn key_bits_roundtrip() {
let key = Key::<()>::from_bits(0x1BAD_CAFE_DEAD_BEEF).unwrap();
assert_eq!(key.to_bits(), 0x1BAD_CAFE_DEAD_BEEF);
}
#[test]
fn key_bits_none_on_zero_generation() {
let key = Key::<()>::from_bits(0x0000_0000_DEAD_BEEF);
assert_eq!(key, None);
}
}