use std::io::{BufRead, Error, Result};
use byteorder::ReadBytesExt;
pub trait ReadBits {
fn get(&mut self, cbit: u32, reader: &mut impl BufRead) -> Result<u32>;
fn peek_byte(&self) -> u8;
fn bits_left(&self) -> u32;
fn consume(&mut self, cbit: u32);
}
#[derive(Debug, Clone)]
pub struct BitReader {
bits: u64,
bits_left: u32,
read_ahead: u32,
}
impl BitReader {
pub fn new() -> Self {
BitReader {
bits: 0,
bits_left: 0,
read_ahead: 0,
}
}
pub fn read_padding_bits(&mut self) -> u8 {
let cbit = self.bits_left & 7;
let wret = self.bits & ((1 << cbit) - 1);
self.bits >>= cbit;
self.bits_left -= cbit;
wret as u8
}
pub fn read_ahead(&mut self, reader: &mut impl BufRead) {
if let Ok(buffer) = reader.fill_buf() {
let buffer = &buffer[self.read_ahead as usize..];
if buffer.len() > 8 {
let mut i = 0;
while self.bits_left <= 56 {
let b = buffer[i] as u64;
self.bits |= b << self.bits_left;
self.bits_left += 8;
i += 1;
}
self.read_ahead += i as u32;
}
}
}
pub fn undo_read_ahead(&mut self, reader: &mut impl BufRead) {
while self.bits_left >= 8 && self.read_ahead > 0 {
self.bits_left -= 8;
self.read_ahead -= 1;
}
self.bits = self.bits & ((1 << self.bits_left) - 1);
if self.read_ahead > 0 {
reader.consume(self.read_ahead as usize);
self.read_ahead = 0;
}
}
#[cold]
fn get_fill_register(
&mut self,
cbit: u32,
reader: &mut impl BufRead,
) -> std::result::Result<u32, Error> {
reader.consume(self.read_ahead as usize);
self.read_ahead = 0;
while self.bits_left < cbit {
let b = reader.read_u8()? as u64;
self.bits |= b << self.bits_left;
self.bits_left += 8;
}
let wret = self.bits & ((1 << cbit) - 1);
self.bits >>= cbit;
self.bits_left -= cbit;
Ok(wret as u32)
}
}
impl ReadBits for BitReader {
fn bits_left(&self) -> u32 {
self.bits_left
}
fn consume(&mut self, cbit: u32) {
debug_assert!(cbit <= self.bits_left);
self.bits >>= cbit;
self.bits_left -= cbit;
}
fn peek_byte(&self) -> u8 {
debug_assert!(self.bits_left >= 8);
self.bits as u8
}
#[inline]
fn get(&mut self, cbit: u32, reader: &mut impl BufRead) -> Result<u32> {
let mask = (1u64 << cbit) - 1;
if cbit < self.bits_left {
let wret = self.bits & mask;
self.bits >>= cbit;
self.bits_left -= cbit;
return Ok(wret as u32);
}
self.get_fill_register(cbit, reader)
}
}