use crate::error::Error;
const BITBUF_WIDTH: u32 = 32;
#[derive(Debug, Clone, Copy, Default)]
pub(crate) struct BitReader {
bit_buffer: u32,
bits_left: u32,
byte_pos: usize,
eof_padding_used: bool,
eof: bool,
}
impl BitReader {
pub(crate) const fn new() -> Self {
Self {
bit_buffer: 0,
bits_left: 0,
byte_pos: 0,
eof_padding_used: false,
eof: false,
}
}
pub(crate) fn byte_pos(&self) -> usize {
self.byte_pos
}
pub(crate) fn set_eof(&mut self, eof: bool) {
self.eof = eof;
}
fn read_bytes(&mut self, buf: &[u8]) -> Result<(), Error> {
if self.byte_pos + 2 <= buf.len() {
let b0 = buf[self.byte_pos] as u32;
let b1 = buf[self.byte_pos + 1] as u32;
self.byte_pos += 2;
let combined = (b0 << 8) | b1;
self.bit_buffer |= combined << (BITBUF_WIDTH - 16 - self.bits_left);
self.bits_left += 16;
Ok(())
} else if self.eof && !self.eof_padding_used {
self.eof_padding_used = true;
self.bits_left += 16;
Ok(())
} else {
Err(Error::UnexpectedEnd)
}
}
pub(crate) fn ensure_bits(&mut self, nbits: u32, buf: &[u8]) -> Result<(), Error> {
debug_assert!(nbits <= 16);
while self.bits_left < nbits {
self.read_bytes(buf)?;
}
Ok(())
}
pub(crate) fn peek_bits(&self, nbits: u32) -> u32 {
debug_assert!((1..=16).contains(&nbits));
self.bit_buffer >> (BITBUF_WIDTH - nbits)
}
pub(crate) fn remove_bits(&mut self, nbits: u32) {
debug_assert!(nbits <= self.bits_left);
if nbits == BITBUF_WIDTH {
self.bit_buffer = 0;
} else {
self.bit_buffer <<= nbits;
}
self.bits_left -= nbits;
}
pub(crate) fn read_bits(&mut self, nbits: u32, buf: &[u8]) -> Result<u32, Error> {
self.ensure_bits(nbits, buf)?;
let v = self.peek_bits(nbits);
self.remove_bits(nbits);
Ok(v)
}
pub(crate) fn read_many_bits(&mut self, bits: u32, buf: &[u8]) -> Result<u32, Error> {
debug_assert!(bits <= 32);
let mut needed = bits;
let mut val: u32 = 0;
while needed > 0 {
if self.bits_left <= BITBUF_WIDTH - 16 {
self.read_bytes(buf)?;
}
let bitrun = self.bits_left.min(needed);
debug_assert!(bitrun >= 1);
val = (val << bitrun) | self.peek_bits(bitrun);
self.remove_bits(bitrun);
needed -= bitrun;
}
Ok(val)
}
pub(crate) fn rebase(&mut self, drop_bytes: usize) {
debug_assert!(drop_bytes <= self.byte_pos);
self.byte_pos -= drop_bytes;
}
pub(crate) fn bits_left(&self) -> u32 {
self.bits_left
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn reads_one_bit_at_a_time_msb_first() {
let buf = [0b1011_0001u8, 0b0110_1010u8];
let mut br = BitReader::new();
let bits: Vec<u32> = (0..16).map(|_| br.read_bits(1, &buf).unwrap()).collect();
assert_eq!(bits, vec![1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0]);
}
#[test]
fn reads_groups_of_bits() {
let buf = [0xAB, 0xCD];
let mut br = BitReader::new();
assert_eq!(br.read_bits(4, &buf).unwrap(), 0xA);
assert_eq!(br.read_bits(8, &buf).unwrap(), 0xBC);
assert_eq!(br.read_bits(4, &buf).unwrap(), 0xD);
}
#[test]
fn read_many_handles_more_than_16_bits() {
let buf = [0xAA, 0xBB, 0xCC, 0x00];
let mut br = BitReader::new();
let v = br.read_many_bits(24, &buf).unwrap();
assert_eq!(v, 0xAA_BB_CC);
}
#[test]
fn returns_unexpected_end_when_buf_short() {
let buf = [0x12];
let mut br = BitReader::new();
assert_eq!(
br.read_bits(1, &buf).unwrap_err(),
crate::error::Error::UnexpectedEnd
);
}
#[test]
fn rebase_keeps_byte_pos_consistent() {
let buf = [0xFF, 0x00, 0xAA, 0xBB];
let mut br = BitReader::new();
let _ = br.read_bits(16, &buf).unwrap();
assert_eq!(br.byte_pos(), 2);
br.rebase(2);
assert_eq!(br.byte_pos(), 0);
let v = br.read_bits(16, &buf[2..]).unwrap();
assert_eq!(v, 0xAABB);
}
}