pub struct BitPump<'a> {
data: &'a [u8],
pos: usize,
bits: u64, bits_left: u32, }
impl<'a> BitPump<'a> {
pub fn new(data: &'a [u8]) -> Self {
let mut pump = Self {
data,
pos: 0,
bits: 0,
bits_left: 0,
};
pump.fill();
pump
}
fn fill(&mut self) {
while self.bits_left <= 56 {
if self.pos >= self.data.len() {
break;
}
let remaining = self.data.len() - self.pos;
if remaining >= 8 {
let bytes_to_add = ((64 - self.bits_left) / 8) as usize;
if bytes_to_add >= 4 {
let mut buf = [0u8; 8];
buf.copy_from_slice(&self.data[self.pos..self.pos + 8]);
let chunk = u64::from_be_bytes(buf);
let v = !chunk;
let has_zero = (v.wrapping_sub(0x0101010101010101)) & (!v) & 0x8080808080808080;
if has_zero == 0 {
let shift = (8 - bytes_to_add) * 8;
let val = chunk >> shift;
let bits_added = bytes_to_add * 8;
if bits_added == 64 {
self.bits = val;
} else {
self.bits = (self.bits << bits_added) | val;
}
self.bits_left += (bytes_to_add * 8) as u32;
self.pos += bytes_to_add;
continue;
}
}
}
let byte = self.data[self.pos] as u64;
self.pos += 1;
if byte == 0xFF && self.pos < self.data.len() {
let next = self.data[self.pos];
if next == 0x00 {
self.pos += 1; } else if (0xD0..=0xD7).contains(&next) {
self.pos += 1;
continue;
} else if next == 0xD9 {
break;
}
}
self.bits = (self.bits << 8) | byte;
self.bits_left += 8;
}
}
#[inline]
pub fn peek(&mut self, n: u32) -> u32 {
if n == 0 {
return 0;
}
if self.bits_left < n {
self.fill();
}
if self.bits_left < n {
return (self.bits as u32) << (n - self.bits_left);
}
((self.bits >> (self.bits_left - n)) & ((1u64 << n) - 1)) as u32
}
#[inline]
pub fn consume(&mut self, n: u32) {
if n <= self.bits_left {
self.bits_left -= n;
} else {
self.bits_left = 0;
}
if self.bits_left < 32 {
self.fill();
}
}
#[inline]
pub fn get_bits(&mut self, n: u32) -> u32 {
let val = self.peek(n);
self.consume(n);
val
}
#[inline]
#[allow(dead_code)]
pub fn position(&self) -> usize {
self.pos
}
#[inline]
#[allow(dead_code)]
pub fn bits_available(&self) -> u32 {
self.bits_left
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bit_pump_basic() {
let data = [0xAB, 0xCD];
let mut pump = BitPump::new(&data);
assert_eq!(pump.get_bits(4), 0b1010);
assert_eq!(pump.get_bits(4), 0b1011);
assert_eq!(pump.get_bits(8), 0xCD);
}
#[test]
fn test_bit_pump_byte_stuffing() {
let data = [0xFF, 0x00, 0xAB];
let mut pump = BitPump::new(&data);
assert_eq!(pump.get_bits(8), 0xFF);
assert_eq!(pump.get_bits(8), 0xAB);
}
#[test]
fn test_bit_pump_peek() {
let data = [0xAB];
let mut pump = BitPump::new(&data);
assert_eq!(pump.peek(4), 0b1010);
assert_eq!(pump.peek(4), 0b1010);
assert_eq!(pump.get_bits(4), 0b1010);
assert_eq!(pump.peek(4), 0b1011);
}
#[test]
fn test_bit_pump_fast_path() {
let data: Vec<u8> = (0..16).map(|i| i as u8).collect();
let mut pump = BitPump::new(&data);
let val1 = pump.get_bits(32);
let val2 = pump.get_bits(32);
assert_eq!(val1, 0x00010203);
assert_eq!(val2, 0x04050607);
let val3 = pump.get_bits(32);
let val4 = pump.get_bits(32);
assert_eq!(val3, 0x08090A0B);
assert_eq!(val4, 0x0C0D0E0F);
}
#[test]
fn test_bit_pump_fast_path_with_stuffing() {
let data = [
0x00, 0x01, 0x02, 0x03, 0xFF, 0x00, 0x05, 0x06, 0x07, 0x08, 0x09,
];
let mut pump = BitPump::new(&data);
assert_eq!(pump.get_bits(32), 0x00010203);
assert_eq!(pump.get_bits(32), 0xFF050607);
}
}