extern crate base2;
extern crate int;
fn fold_size<R>(
mut size: u8,
f: &mut FnMut(u8, u8, R) -> std::io::Result<R>,
mut result: R
) -> std::io::Result<R> {
let mut offset = 0;
while size >= 8 {
result = f(offset, 8, result)?;
offset += 8;
size -= 8;
}
if size > 0 {
result = f(offset, size, result)?;
}
Ok(result)
}
pub struct BitWrite<'t> {
w: &'t mut std::io::Write,
buffer: u8,
size: u8,
}
impl BitWrite<'_> {
fn write_buffer(&mut self) -> std::io::Result<()> {
self.w.write_all(&[self.buffer])
}
fn io_drop(&mut self) -> std::io::Result<()> {
if self.size > 0 {
self.write_buffer()?;
self.size = 0;
}
Ok(())
}
pub fn write_u8(&mut self, mut value: u8, size: u8) -> std::io::Result<()> {
use base2::Base2;
value &= u8::mask(size);
self.buffer |= if self.size == 8 { 0 } else { value << self.size };
self.size += size;
if self.size >= 8 {
self.write_buffer()?;
self.size -= 8;
let offset = size - self.size;
self.buffer = if offset == 8 { 0 } else { value >> offset };
}
Ok(())
}
pub fn write<T: int::UInt>(&mut self, value: T, size: u8) -> std::io::Result<()> {
fold_size(
size,
&mut |o, s, _| self.write_u8((value >> o).as_(), s),
()
)
}
}
impl Drop for BitWrite<'_> {
fn drop(&mut self) {
let _ignore_error = self.io_drop();
}
}
pub trait UseBitWrite: Sized + std::io::Write {
fn use_bit_write<R>(
&mut self,
f: &mut Fn(&mut BitWrite) -> std::io::Result<R>
) -> std::io::Result<R> {
let mut adapter = BitWrite { w: self, buffer: 0, size: 0 };
let result = f(&mut adapter)?;
adapter.io_drop()?;
Ok(result)
}
}
pub fn use_bit_write_mem(f: &mut Fn(&mut BitWrite) -> std::io::Result<()>) -> std::io::Result<Vec<u8>> {
let mut result = vec![];
{
std::io::Cursor::new(&mut result).use_bit_write(f)?;
}
Ok(result)
}
impl<T: std::io::Write> UseBitWrite for T {}
pub struct BitRead<'t> {
r: &'t mut std::io::Read,
buffer: u8,
size: u8,
}
impl BitRead<'_> {
fn read_u8(&mut self, size: u8) -> std::io::Result<u8> {
use base2::Base2;
let b16 = if self.size >= size {
self.buffer as u16
} else {
let mut b = [0];
self.r.read_exact(&mut b)?;
let result = ((b[0] as u16) << self.size) | (self.buffer as u16);
self.size += 8;
result
};
self.size -= size;
self.buffer = (b16 >> size) as u8;
Ok((b16 & u16::mask(size)) as u8)
}
pub fn read<T: int::UInt>(&mut self, size: u8) -> std::io::Result<T> {
fold_size(
size,
&mut |o, s, r| Ok(r | (T::from_u8(self.read_u8(s)?) << o)),
T::_0
)
}
}
pub trait UseBitRead: Sized + std::io::Read {
fn use_bit_read(&mut self) -> BitRead {
BitRead { r: self, buffer: 0, size: 0 }
}
}
impl<T: std::io::Read> UseBitRead for T {}