use crate::error::{Error, Result};
#[derive(Debug)]
pub struct BitReader<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> BitReader<'a> {
pub const fn new(data: &'a [u8]) -> Self {
BitReader { data, pos: 0 }
}
pub const fn remaining_bits(&self) -> usize {
self.data.len() * 8 - self.pos
}
pub const fn bit_position(&self) -> usize {
self.pos
}
pub const fn is_aligned(&self) -> bool {
self.pos % 8 == 0
}
pub fn byte_align(&mut self) {
self.pos = self.pos.div_ceil(8) * 8;
}
pub fn bits(&mut self, n: usize) -> Result<u64> {
if n > 64 {
return Err(Error::BadValue("bit width over 64"));
}
if n > self.remaining_bits() {
return Err(Error::truncated("bits", n, self.remaining_bits()));
}
if n == 0 {
return Ok(0);
}
if n <= 8 - (self.pos % 8) {
let off = self.pos % 8;
let byte = self.data[self.pos / 8];
let v = (byte >> (8 - off - n)) & (0xFFu8 >> (8 - n));
self.pos += n;
return Ok(u64::from(v));
}
let byte_pos = self.pos / 8;
let head_bits = (8 - self.pos % 8) % 8; let mut value = if head_bits == 0 {
0u64
} else {
u64::from(self.data[byte_pos] & ((1u8 << head_bits) - 1))
};
let mut left = n - head_bits;
let mut i = byte_pos + usize::from(head_bits != 0);
while left >= 8 {
value = (value << 8) | u64::from(self.data[i]);
i += 1;
left -= 8;
}
if left > 0 {
let v = self.data[i] >> (8 - left);
value = (value << left) | u64::from(v);
}
self.pos += n;
Ok(value)
}
pub fn byte(&mut self) -> Result<u8> {
if !self.is_aligned() {
return Err(Error::BadValue("unaligned byte read"));
}
if self.remaining_bits() < 8 {
return Err(Error::truncated("byte", 8, self.remaining_bits()));
}
let byte = self.data[self.pos / 8];
self.pos += 8;
Ok(byte)
}
}