use core::num::NonZero;
use crate::{DescendError, Internal, IntoKeys, Key, KeyError, Keys, Schema, Transcode};
#[derive(
Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, serde::Serialize, serde::Deserialize,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct Packed(pub NonZero<usize>);
impl Default for Packed {
fn default() -> Self {
Self::EMPTY
}
}
const TWO: NonZero<usize> = NonZero::<usize>::MIN.saturating_add(1);
impl Packed {
pub const BITS: u32 = NonZero::<usize>::BITS;
pub const CAPACITY: u32 = Self::BITS - 1;
pub const EMPTY: Self = Self(
TWO.saturating_pow(Self::CAPACITY),
);
pub const fn new(value: usize) -> Option<Self> {
match NonZero::new(value) {
Some(value) => Some(Self(value)),
None => None,
}
}
pub const fn new_from_lsb(value: usize) -> Option<Self> {
match NonZero::new(value) {
Some(value) => Some(Self::from_lsb(value)),
None => None,
}
}
pub const fn get(&self) -> usize {
self.0.get()
}
pub const fn is_empty(&self) -> bool {
matches!(*self, Self::EMPTY)
}
pub const fn len(&self) -> u32 {
Self::CAPACITY - self.0.trailing_zeros()
}
pub const fn into_lsb(self) -> NonZero<usize> {
TWO.saturating_pow(self.len())
.saturating_add((self.get() >> 1) >> self.0.trailing_zeros())
}
pub const fn from_lsb(value: NonZero<usize>) -> Self {
Self(
TWO.saturating_pow(value.leading_zeros())
.saturating_add((value.get() << 1) << value.leading_zeros()),
)
}
pub const fn bits_for(num: usize) -> u32 {
match usize::BITS - num.leading_zeros() {
0 => 1,
v => v,
}
}
pub fn pop_msb(&mut self, bits: u32) -> Option<usize> {
let s = self.get();
Self::new(s << bits).map(|new| {
*self = new;
(s >> (Self::CAPACITY - bits)) >> 1
})
}
pub fn push_lsb(&mut self, bits: u32, value: usize) -> Option<u32> {
debug_assert_eq!(value >> bits, 0);
let mut n = self.0.trailing_zeros();
let old_marker = 1 << n;
Self::new(old_marker >> bits).map(|new_marker| {
n -= bits;
self.0 = (self.get() ^ old_marker) | ((value << n) << 1) | new_marker.0;
n
})
}
}
impl core::fmt::Display for Packed {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl Keys for Packed {
fn next(&mut self, internal: &Internal) -> Result<usize, KeyError> {
let bits = Self::bits_for(internal.len().get() - 1);
let index = self.pop_msb(bits).ok_or(KeyError::TooShort)?;
index.find(internal).ok_or(KeyError::NotFound)
}
fn finalize(&mut self) -> Result<(), KeyError> {
if self.is_empty() {
Ok(())
} else {
Err(KeyError::TooLong)
}
}
}
impl IntoKeys for Packed {
type IntoKeys = Self;
fn into_keys(self) -> Self::IntoKeys {
self
}
}
impl Transcode for Packed {
type Error = ();
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_schema| {
if let Some((index, internal)) = idx_schema {
let bits = Packed::bits_for(internal.len().get() - 1);
self.push_lsb(bits, index).ok_or(())?;
}
Ok(())
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test() {
let t = [1usize, 3, 4, 0, 1];
let mut p = Packed::EMPTY;
for t in t {
let bits = Packed::bits_for(t);
p.push_lsb(bits, t).unwrap();
}
for t in t {
let bits = Packed::bits_for(t);
assert_eq!(p.pop_msb(bits).unwrap(), t);
}
}
}