use crate::decompressor::core::data::corrupt;
use crate::decompressor::error::DecodeError;
#[derive(Debug)]
pub(super) struct Reverse<'a> {
data: &'a [u8],
remaining: i64,
}
impl<'a> Reverse<'a> {
pub(super) fn new(data: &'a [u8]) -> Result<Self, DecodeError> {
let last = *data.last().ok_or_else(corrupt)?;
if last == 0 {
return Err(corrupt());
}
let payload = i64::from(7 - last.leading_zeros());
let whole = (data.len() as i64 - 1).saturating_mul(8);
Ok(Self {
data,
remaining: whole.saturating_add(payload),
})
}
pub(super) const fn at(data: &'a [u8], remaining: i64) -> Self {
Self { data, remaining }
}
pub(super) const fn remaining(&self) -> i64 {
self.remaining
}
#[inline]
pub(super) fn peek(&self, n: u32) -> u32 {
let low = self.remaining - i64::from(n);
if low >= 0 {
self.window(low as u64, n)
} else if self.remaining > 0 {
self.window(0, self.remaining as u32) << (-low)
} else {
0
}
}
#[inline]
pub(super) const fn skip(&mut self, n: u32) {
self.remaining -= n as i64;
}
#[inline]
pub(super) fn read(&mut self, n: u32) -> u32 {
let value = self.peek(n);
self.skip(n);
value
}
#[inline]
fn window(&self, low: u64, n: u32) -> u32 {
let byte = (low >> 3) as usize;
let word = match self.data.get(byte..).and_then(<[u8]>::first_chunk::<8>) {
Some(chunk) => u64::from_le_bytes(*chunk),
None => {
let mut chunk = [0u8; 8];
let tail = self.data.get(byte..).unwrap_or_default();
chunk[..tail.len().min(8)].copy_from_slice(&tail[..tail.len().min(8)]);
u64::from_le_bytes(chunk)
}
};
((word >> (low & 7)) & ((1u64 << n) - 1)) as u32
}
}
#[inline(always)]
pub(super) fn refill(src: &[u8], pos: i64) -> Option<u64> {
let at = usize::try_from((pos >> 3) - 7).ok()?;
let chunk = src.get(at..)?.first_chunk::<8>()?;
Some(u64::from_le_bytes(*chunk) << (8 - (pos & 7)))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn end_marks_are_required() {
assert_eq!(Reverse::new(&[]).unwrap_err(), corrupt());
assert_eq!(Reverse::new(&[1, 0]).unwrap_err(), corrupt());
assert_eq!(Reverse::new(&[0xff, 1]).unwrap().remaining(), 8);
}
#[test]
fn values_come_back_in_reverse_order() {
let value = 0b101 | (0b01 << 3) | (0xAB << 5) | (1 << 13);
let bytes = [value as u8, (value >> 8) as u8];
let mut bits = Reverse::new(&bytes).unwrap();
assert_eq!(bits.remaining(), 13);
assert_eq!(bits.read(8), 0xAB);
assert_eq!(bits.read(2), 0b01);
assert_eq!(bits.peek(3), 0b101);
bits.skip(3);
assert_eq!(bits.remaining(), 0);
}
#[test]
fn over_reads_are_zero_filled_and_visible() {
let mut bits = Reverse::new(&[0b101]).unwrap();
assert_eq!(bits.remaining(), 2);
assert_eq!(bits.peek(4), 0b0100);
assert_eq!(bits.read(3), 0b010);
assert_eq!(bits.remaining(), -1);
assert_eq!(bits.peek(3), 0);
}
#[test]
fn long_streams_read_across_word_boundaries() {
let mut data: alloc::vec::Vec<u8> = (0..40u8).map(|i| i.wrapping_mul(37) | 1).collect();
data[39] = 0x80;
let mut bits = Reverse::new(&data).unwrap();
assert_eq!(bits.remaining(), 39 * 8 + 7);
let mut total = 0;
while bits.remaining() > 12 {
bits.read(12);
total += 12;
}
assert!(total > 300);
let mut short = Reverse::new(&[0xff, 0xff, 0xff]).unwrap();
assert_eq!(short.read(7), 0x7f);
assert_eq!(short.read(16), 0xffff);
assert_eq!(short.remaining(), 0);
}
}