use crate::key_piece::KeyPiece;
use core::hash::Hash;
use core::marker::PhantomData;
pub unsafe trait KeyLayout<Idx: KeyPiece, Gen: KeyPiece> {
type Repr: Copy + Eq + Hash + Send + Sync + 'static;
fn max_idx() -> Idx;
fn max_generation() -> Gen;
unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> Self::Repr;
fn idx(repr: Self::Repr) -> Idx;
fn generation(repr: Self::Repr) -> Gen::NonZero;
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Split;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SplitRepr<Idx: KeyPiece, Gen: KeyPiece> {
idx: Idx,
generation: Gen::NonZero,
}
unsafe impl<Idx: KeyPiece, Gen: KeyPiece> KeyLayout<Idx, Gen> for Split {
type Repr = SplitRepr<Idx, Gen>;
#[inline]
fn max_idx() -> Idx {
Idx::MAX
}
#[inline]
fn max_generation() -> Gen {
Gen::MAX
}
#[inline]
unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> SplitRepr<Idx, Gen> {
debug_assert!(generation.is_odd());
let generation = unsafe { generation.into_non_zero_unchecked() };
SplitRepr { idx, generation }
}
#[inline]
fn idx(repr: SplitRepr<Idx, Gen>) -> Idx {
repr.idx
}
#[inline]
fn generation(repr: SplitRepr<Idx, Gen>) -> Gen::NonZero {
repr.generation
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Packed<R, const GEN_BITS: u32>(PhantomData<R>);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PackedRepr<R: KeyPiece>(R::NonZero);
#[inline(always)]
fn check_packed<Idx: KeyPiece, Gen: KeyPiece, R: KeyPiece, const GEN_BITS: u32>() {
const {
assert!(GEN_BITS >= 1, "Packed needs at least one generation bit");
assert!(GEN_BITS < R::BITS, "Packed needs at least one index bit");
assert!(
Gen::BITS >= GEN_BITS,
"the Gen type of the config has fewer bits than GEN_BITS"
);
assert!(
Idx::BITS >= R::BITS - GEN_BITS,
"the Idx type of the config has fewer bits than the index field"
);
}
}
#[inline]
fn low_bits(bits: u32) -> u128 {
debug_assert!(bits < 128);
(1u128 << bits) - 1
}
unsafe impl<Idx: KeyPiece, Gen: KeyPiece, R: KeyPiece, const GEN_BITS: u32> KeyLayout<Idx, Gen>
for Packed<R, GEN_BITS>
{
type Repr = PackedRepr<R>;
#[inline]
fn max_idx() -> Idx {
check_packed::<Idx, Gen, R, GEN_BITS>();
unsafe { Idx::from_u128_unchecked(low_bits(R::BITS - GEN_BITS)) }
}
#[inline]
fn max_generation() -> Gen {
check_packed::<Idx, Gen, R, GEN_BITS>();
unsafe { Gen::from_u128_unchecked(low_bits(GEN_BITS)) }
}
#[inline]
unsafe fn pack_unchecked(idx: Idx, generation: Gen) -> PackedRepr<R> {
check_packed::<Idx, Gen, R, GEN_BITS>();
debug_assert!(idx <= <Self as KeyLayout<Idx, Gen>>::max_idx());
debug_assert!(generation.is_odd());
debug_assert!(generation <= <Self as KeyLayout<Idx, Gen>>::max_generation());
let bits = (idx.into_u128() << GEN_BITS) | generation.into_u128();
PackedRepr(unsafe { R::from_u128_unchecked(bits).into_non_zero_unchecked() })
}
#[inline]
fn idx(repr: PackedRepr<R>) -> Idx {
check_packed::<Idx, Gen, R, GEN_BITS>();
unsafe { Idx::from_u128_unchecked(R::from_non_zero(repr.0).into_u128() >> GEN_BITS) }
}
#[inline]
fn generation(repr: PackedRepr<R>) -> Gen::NonZero {
check_packed::<Idx, Gen, R, GEN_BITS>();
unsafe {
Gen::from_u128_unchecked(R::from_non_zero(repr.0).into_u128() & low_bits(GEN_BITS))
.into_non_zero_unchecked()
}
}
}