use crate::error::Error;
#[derive(Debug, Clone, Default)]
pub struct BitReader {
buf: alloc::vec::Vec<u8>,
byte_pos: usize,
acc: u64,
nbits: u32,
}
impl BitReader {
pub fn new() -> Self {
Self::default()
}
pub fn feed_slice(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes);
}
fn refill(&mut self) {
while self.nbits <= 56 && self.byte_pos < self.buf.len() {
let b = self.buf[self.byte_pos] as u64;
self.byte_pos += 1;
self.acc |= b << (56 - self.nbits);
self.nbits += 8;
}
}
pub fn peek(&mut self, n: u32) -> Result<u32, Error> {
debug_assert!(n <= 32);
if n == 0 {
return Ok(0);
}
if self.nbits < n {
self.refill();
}
if self.nbits < n {
return Err(Error::UnexpectedEnd);
}
Ok(((self.acc >> (64 - n)) & ((1u64 << n) - 1)) as u32)
}
pub fn drop_bits(&mut self, n: u32) -> Result<(), Error> {
debug_assert!(n <= 32);
if n == 0 {
return Ok(());
}
if self.nbits < n {
self.refill();
}
if self.nbits < n {
return Err(Error::UnexpectedEnd);
}
self.acc <<= n;
self.nbits -= n;
Ok(())
}
pub fn read_bits(&mut self, n: u32) -> Result<u32, Error> {
let v = self.peek(n)?;
self.drop_bits(n)?;
Ok(v)
}
pub fn byte_align(&mut self) {
let drop = self.nbits & 7;
if drop > 0 {
let _ = self.drop_bits(drop);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
extern crate std;
#[test]
fn msb_first_within_byte() {
let mut r = BitReader::new();
r.feed_slice(&[0xAB, 0xCD]);
assert_eq!(r.read_bits(4).unwrap(), 0xA);
assert_eq!(r.read_bits(4).unwrap(), 0xB);
assert_eq!(r.read_bits(8).unwrap(), 0xCD);
}
#[test]
fn read_across_bytes() {
let mut r = BitReader::new();
r.feed_slice(&[0xAB, 0xCD]);
assert_eq!(r.read_bits(12).unwrap(), 0xABC);
assert_eq!(r.read_bits(4).unwrap(), 0xD);
}
#[test]
fn byte_align_discards_partial_byte() {
let mut r = BitReader::new();
r.feed_slice(&[0xAB, 0xCD]);
r.drop_bits(3).unwrap();
r.byte_align();
assert_eq!(r.read_bits(8).unwrap(), 0xCD);
}
#[test]
fn underflow_yields_unexpected_end() {
let mut r = BitReader::new();
r.feed_slice(&[0xFF]);
assert_eq!(r.read_bits(8).unwrap(), 0xFF);
assert!(matches!(r.read_bits(1), Err(Error::UnexpectedEnd)));
}
#[test]
fn peek_does_not_consume() {
let mut r = BitReader::new();
r.feed_slice(&[0x12, 0x34]);
assert_eq!(r.peek(8).unwrap(), 0x12);
assert_eq!(r.peek(8).unwrap(), 0x12);
r.drop_bits(8).unwrap();
assert_eq!(r.peek(8).unwrap(), 0x34);
}
}