use crate::error::Error;
pub(crate) struct BitReader<'a> {
data: &'a [u8],
bit_pos: usize,
}
impl<'a> BitReader<'a> {
pub(crate) fn new(data: &'a [u8]) -> Self {
Self { data, bit_pos: 0 }
}
pub(crate) fn bits_remaining(&self) -> usize {
(self.data.len() * 8).saturating_sub(self.bit_pos)
}
#[inline]
pub(crate) fn read_bit(&mut self) -> Result<u32, Error> {
let byte_idx = self.bit_pos >> 3;
if byte_idx >= self.data.len() {
return Err(Error::UnexpectedEnd);
}
let bit = (self.data[byte_idx] >> (self.bit_pos & 7)) & 1;
self.bit_pos += 1;
Ok(bit as u32)
}
pub(crate) fn read_bits(&mut self, n: u32) -> Result<u32, Error> {
debug_assert!(n <= 32);
if n == 0 {
return Ok(0);
}
if self.bits_remaining() < n as usize {
return Err(Error::UnexpectedEnd);
}
let mut value: u32 = 0;
for i in 0..n {
let bit = self.read_bit()?;
value |= bit << i;
}
Ok(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lsb_first_single_bits() {
let data = [0b1011_0001u8];
let mut r = BitReader::new(&data);
for expected in [1u32, 0, 0, 0, 1, 1, 0, 1] {
assert_eq!(r.read_bit().unwrap(), expected);
}
assert!(matches!(r.read_bit(), Err(Error::UnexpectedEnd)));
}
#[test]
fn lsb_first_multibit_field() {
let data = [0xABu8, 0xCD];
let mut r = BitReader::new(&data);
assert_eq!(r.read_bits(4).unwrap(), 0xB);
assert_eq!(r.read_bits(4).unwrap(), 0xA);
assert_eq!(r.read_bits(4).unwrap(), 0xD);
assert_eq!(r.read_bits(4).unwrap(), 0xC);
}
#[test]
fn read_across_byte_boundary() {
let data = [0x01u8, 0x00];
let mut r = BitReader::new(&data);
assert_eq!(r.read_bits(9).unwrap(), 1);
}
#[test]
fn underrun_is_clean() {
let data = [0xFFu8];
let mut r = BitReader::new(&data);
assert!(matches!(r.read_bits(16), Err(Error::UnexpectedEnd)));
}
#[test]
fn zero_bits_is_zero() {
let data = [0xFFu8];
let mut r = BitReader::new(&data);
assert_eq!(r.read_bits(0).unwrap(), 0);
}
}