use crate::config::KeyConfig;
use crate::key_piece::KeyPiece;
use crate::parity::Odd;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Split<Idx: KeyPiece = u32, Gen: KeyPiece = u32> {
idx: Idx,
generation: Odd<Gen>,
}
unsafe impl<Idx: KeyPiece, Gen: KeyPiece> KeyConfig for Split<Idx, Gen> {
type Idx = Idx;
type Gen = Gen;
#[inline]
fn max_idx() -> Idx {
Idx::MAX
}
#[inline]
fn max_generation() -> Odd<Gen> {
unsafe { Odd::new_unchecked(Gen::MAX) }
}
#[inline]
unsafe fn pack_unchecked(idx: Idx, generation: Odd<Gen>) -> Self {
Self { idx, generation }
}
#[inline]
fn idx(self) -> Idx {
self.idx
}
#[inline]
fn generation(self) -> Odd<Gen> {
self.generation
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Packed<R: KeyPiece, const GEN_BITS: u32>(
R::NonZero,
);
mod sealed {
use crate::key_piece::KeyPiece;
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a key config",
label = "not a key config",
note = "`Packed<R, GEN_BITS>` needs `R` to be `u8`, `u16`, `u32`, `u64` or `u128`, and `GEN_BITS` to be at least 1 and less than the bits of `R`"
)]
pub trait PackedParts {
type Index: KeyPiece;
type Generation: KeyPiece;
}
}
macro_rules! packed_table {
($callback:ident) => {
$callback! {
u8 {
u8, u8 => 1 2 3 4 5 6 7;
}
u16 {
u16, u8 => 1 2 3 4 5 6 7;
u8, u8 => 8;
u8, u16 => 9 10 11 12 13 14 15;
}
u32 {
u32, u8 => 1 2 3 4 5 6 7 8;
u32, u16 => 9 10 11 12 13 14 15;
u16, u16 => 16;
u16, u32 => 17 18 19 20 21 22 23;
u8, u32 => 24 25 26 27 28 29 30 31;
}
u64 {
u64, u8 => 1 2 3 4 5 6 7 8;
u64, u16 => 9 10 11 12 13 14 15 16;
u64, u32 => 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31;
u32, u32 => 32;
u32, u64 => 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47;
u16, u64 => 48 49 50 51 52 53 54 55;
u8, u64 => 56 57 58 59 60 61 62 63;
}
u128 {
u128, u8 => 1 2 3 4 5 6 7 8;
u128, u16 => 9 10 11 12 13 14 15 16;
u128, u32 => 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32;
u128, u64 => 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
54 55 56 57 58 59 60 61 62 63;
u64, u64 => 64;
u64, u128 => 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
86 87 88 89 90 91 92 93 94 95;
u32, u128 => 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111;
u16, u128 => 112 113 114 115 116 117 118 119;
u8, u128 => 120 121 122 123 124 125 126 127;
}
}
};
}
macro_rules! impl_packed_parts {
($($r:ty { $($idx:ty, $gen:ty => $($gen_bits:literal)*;)* })*) => {
$($($(
impl sealed::PackedParts for Packed<$r, $gen_bits> {
type Index = $idx;
type Generation = $gen;
}
)*)*)*
};
}
packed_table!(impl_packed_parts);
#[cfg(all(test, feature = "alloc"))]
pub(crate) use packed_table;
#[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 generation type of a Packed key config has fewer bits than GEN_BITS"
);
assert!(
Idx::BITS >= R::BITS - GEN_BITS,
"the index type of a Packed key config has fewer bits than the index field"
);
}
}
#[inline]
fn low_bits(bits: u32) -> u128 {
debug_assert!(bits < 128);
(1u128 << bits) - 1
}
unsafe impl<R: KeyPiece, const GEN_BITS: u32> KeyConfig for Packed<R, GEN_BITS>
where
Self: sealed::PackedParts,
{
type Idx = <Self as sealed::PackedParts>::Index;
type Gen = <Self as sealed::PackedParts>::Generation;
#[inline]
fn max_idx() -> Self::Idx {
check_packed::<Self::Idx, Self::Gen, R, GEN_BITS>();
unsafe { Self::Idx::from_u128_unchecked(low_bits(R::BITS - GEN_BITS)) }
}
#[inline]
fn max_generation() -> Odd<Self::Gen> {
check_packed::<Self::Idx, Self::Gen, R, GEN_BITS>();
unsafe { Odd::new_unchecked(Self::Gen::from_u128_unchecked(low_bits(GEN_BITS))) }
}
#[inline]
unsafe fn pack_unchecked(idx: Self::Idx, generation: Odd<Self::Gen>) -> Self {
check_packed::<Self::Idx, Self::Gen, R, GEN_BITS>();
debug_assert!(idx <= Self::max_idx());
debug_assert!(generation <= Self::max_generation());
let generation = Self::Gen::from_non_zero(generation.get());
let bits = (idx.into_u128() << GEN_BITS) | generation.into_u128();
Self(unsafe { R::from_u128_unchecked(bits).into_non_zero_unchecked() })
}
#[inline]
fn idx(self) -> Self::Idx {
check_packed::<Self::Idx, Self::Gen, R, GEN_BITS>();
unsafe { Self::Idx::from_u128_unchecked(R::from_non_zero(self.0).into_u128() >> GEN_BITS) }
}
#[inline]
fn generation(self) -> Odd<Self::Gen> {
check_packed::<Self::Idx, Self::Gen, R, GEN_BITS>();
unsafe {
Odd::new_unchecked(Self::Gen::from_u128_unchecked(
R::from_non_zero(self.0).into_u128() & low_bits(GEN_BITS),
))
}
}
}