use std::io::{self, Write};
#[cfg(target_pointer_width = "64")]
#[macro_use]
mod arch_dep {
pub type AccType = u64;
pub const FLUSH_AT: u8 = 48;
macro_rules! push {
($s:ident) => {
$s.w.extend_from_slice(
&[
$s.acc as u8,
($s.acc >> 8) as u8,
($s.acc >> 16) as u8,
($s.acc >> 24) as u8,
($s.acc >> 32) as u8,
($s.acc >> 40) as u8,
][..],
)
};
}
}
#[cfg(not(target_pointer_width = "64"))]
#[macro_use]
mod arch_dep {
pub type AccType = u32;
pub const FLUSH_AT: u8 = 16;
macro_rules! push {
($s:ident) => {
$s.w.push($s.acc as u8);
$s.w.push(($s.acc >> 8) as u8);
};
}
}
use self::arch_dep::*;
pub struct LsbWriter {
pub w: Vec<u8>,
bits: u8,
acc: AccType,
}
impl LsbWriter {
pub fn new(writer: Vec<u8>) -> LsbWriter {
LsbWriter {
w: writer,
bits: 0,
acc: 0,
}
}
pub fn pending_bits(&self) -> u8 {
self.bits
}
pub fn write_bits(&mut self, v: u16, n: u8) {
self.acc |= (AccType::from(v)) << self.bits;
self.bits += n;
while self.bits >= FLUSH_AT {
push!(self);
self.acc >>= FLUSH_AT;
self.bits -= FLUSH_AT;
}
}
fn write_bits_finish(&mut self, v: u16, n: u8) {
self.acc |= (AccType::from(v)) << self.bits;
self.bits += n % 8;
while self.bits >= 8 {
self.w.push(self.acc as u8);
self.acc >>= 8;
self.bits -= 8;
}
}
pub fn flush_raw(&mut self) {
let missing = FLUSH_AT - self.bits;
if missing > 0 && self.bits > 0 {
self.write_bits_finish(0, missing);
}
}
}
impl Write for LsbWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.acc == 0 {
self.w.extend_from_slice(buf)
} else {
for &byte in buf.iter() {
self.write_bits(u16::from(byte), 8)
}
}
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.flush_raw();
Ok(())
}
}
#[cfg(test)]
mod test {
use super::LsbWriter;
#[test]
fn write_bits() {
let input = [
(3, 3),
(10, 8),
(88, 7),
(0, 2),
(0, 5),
(0, 0),
(238, 8),
(126, 8),
(161, 8),
(10, 8),
(238, 8),
(174, 8),
(126, 8),
(174, 8),
(65, 8),
(142, 8),
(62, 8),
(10, 8),
(1, 8),
(161, 8),
(78, 8),
(62, 8),
(158, 8),
(206, 8),
(10, 8),
(64, 7),
(0, 0),
(24, 5),
(0, 0),
(174, 8),
(126, 8),
(193, 8),
(174, 8),
];
let expected = [
83, 192, 2, 220, 253, 66, 21, 220, 93, 253, 92, 131, 28, 125, 20, 2, 66, 157, 124, 60,
157, 21, 128, 216, 213, 47, 216, 21,
];
let mut writer = LsbWriter::new(Vec::new());
for v in input.iter() {
writer.write_bits(v.0, v.1);
}
writer.flush_raw();
assert_eq!(writer.w, expected);
}
}
#[cfg(all(test, feature = "benchmarks"))]
mod bench {
use super::LsbWriter;
use test_std::Bencher;
#[bench]
fn bit_writer(b: &mut Bencher) {
let input = [
(3, 3),
(10, 8),
(88, 7),
(0, 2),
(0, 5),
(0, 0),
(238, 8),
(126, 8),
(161, 8),
(10, 8),
(238, 8),
(174, 8),
(126, 8),
(174, 8),
(65, 8),
(142, 8),
(62, 8),
(10, 8),
(1, 8),
(161, 8),
(78, 8),
(62, 8),
(158, 8),
(206, 8),
(10, 8),
(64, 7),
(0, 0),
(24, 5),
(0, 0),
(174, 8),
(126, 8),
(193, 8),
(174, 8),
];
let mut writer = LsbWriter::new(Vec::with_capacity(100));
b.iter(|| {
for v in input.iter() {
let _ = writer.write_bits(v.0, v.1);
}
});
}
}