pub(crate) struct BitWriter {
out: Vec<u8>,
current: u8,
used: u8,
}
impl BitWriter {
pub(crate) fn new() -> Self {
BitWriter {
out: Vec::new(),
current: 0,
used: 0,
}
}
pub(crate) fn is_byte_aligned(&self) -> bool {
self.used == 0
}
pub(crate) fn bytes(&self) -> &[u8] {
&self.out
}
pub(crate) fn write_bits(&mut self, value: u64, n: u32) {
debug_assert!(n <= 64);
let mut remaining = n;
while remaining > 0 {
let free = 8 - self.used; let take = remaining.min(free as u32) as u8;
let shift = remaining - take as u32;
let chunk = ((value >> shift) & ((1u64 << take) - 1)) as u8;
self.current |= chunk << (free - take);
self.used += take;
if self.used == 8 {
self.out.push(self.current);
self.current = 0;
self.used = 0;
}
remaining -= take as u32;
}
}
pub(crate) fn write_unary(&mut self, q: u64) {
let mut left = q;
while left >= 8 {
self.write_bits(0, 8);
left -= 8;
}
self.write_bits(1, left as u32 + 1);
}
pub(crate) fn align_to_byte(&mut self) {
if self.used != 0 {
self.out.push(self.current);
self.current = 0;
self.used = 0;
}
}
pub(crate) fn into_bytes(mut self) -> Vec<u8> {
self.align_to_byte();
self.out
}
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bitstream::BitReader;
#[test]
fn round_trips_through_the_reader() {
let mut w = BitWriter::new();
w.write_bits(0b101, 3);
w.write_bits(0b1111000011, 10);
w.write_bits(0xAB, 8);
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
assert_eq!(r.read_u32(3).unwrap(), 0b101);
assert_eq!(r.read_u32(10).unwrap(), 0b1111000011);
assert_eq!(r.read_u32(8).unwrap(), 0xAB);
}
#[test]
fn unary_round_trips() {
let mut w = BitWriter::new();
for q in [0u64, 1, 5, 9, 20] {
w.write_unary(q);
}
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
for q in [0u64, 1, 5, 9, 20] {
assert_eq!(r.read_unary().unwrap() as u64, q);
}
}
#[test]
fn align_emits_pending_byte() {
let mut w = BitWriter::new();
w.write_bits(0b1, 1);
assert!(!w.is_byte_aligned());
w.align_to_byte();
assert!(w.is_byte_aligned());
assert_eq!(w.bytes().len(), 1);
assert_eq!(w.bytes()[0], 0b1000_0000);
}
#[test]
fn wide_64_bit_write() {
let mut w = BitWriter::new();
w.write_bits(0x1234_5678_9ABC_DEF0, 64);
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
assert_eq!(r.read_u64(64).unwrap(), 0x1234_5678_9ABC_DEF0);
}
}