pub(crate) struct BitWriter {
storage: Vec<u8>,
bits_written: usize,
}
impl BitWriter {
pub(crate) const MAX_BITS_PER_CALL: usize = 56;
pub(crate) fn new() -> Self {
Self {
storage: Vec::new(),
bits_written: 0,
}
}
pub(crate) fn bits_written(&self) -> usize {
self.bits_written
}
pub(crate) fn write(&mut self, n_bits: usize, bits: u64) {
debug_assert!(n_bits <= Self::MAX_BITS_PER_CALL);
debug_assert!(n_bits == 64 || (bits >> n_bits) == 0);
let byte_pos = self.bits_written / 8;
let bit_in_byte = self.bits_written % 8;
let needed = byte_pos + 8;
if self.storage.len() < needed {
self.storage.resize(needed, 0);
}
let shifted = bits << bit_in_byte;
let mut buf = [0u8; 8];
buf.copy_from_slice(&self.storage[byte_pos..byte_pos + 8]);
let mut v = u64::from_le_bytes(buf);
debug_assert!(
v >> bit_in_byte == 0,
"BitWriter invariant violated at byte {}",
byte_pos
);
v |= shifted;
self.storage[byte_pos..byte_pos + 8].copy_from_slice(&v.to_le_bytes());
self.bits_written += n_bits;
}
pub(crate) fn zero_pad_to_byte(&mut self) {
let rem = (8 - (self.bits_written % 8)) % 8;
if rem != 0 {
self.write(rem, 0);
}
debug_assert_eq!(self.bits_written % 8, 0);
}
pub(crate) fn append_byte_aligned(&mut self, others: &mut [BitWriter]) {
let mut extra = 0usize;
for w in others.iter() {
extra += w.bits_written.div_ceil(8);
}
if extra == 0 {
return;
}
debug_assert_eq!(self.bits_written % 8, 0);
for w in others.iter_mut() {
w.zero_pad_to_byte();
}
let mut pos = self.bits_written / 8;
let new_len = pos + extra + 1;
if self.storage.len() < new_len {
self.storage.resize(new_len, 0);
}
for w in others.iter() {
let n = w.bits_written / 8;
if n > 0 {
self.storage[pos..pos + n].copy_from_slice(&w.storage[..n]);
pos += n;
}
}
self.bits_written += extra * 8;
}
pub(crate) fn append(&mut self, other: &BitWriter) {
let full_bytes = other.bits_written / 8;
let trailing_bits = other.bits_written % 8;
for i in 0..full_bytes {
self.write(8, other.storage[i] as u64);
}
if trailing_bits > 0 {
let last = other.storage[full_bytes] as u64;
let mask = (1u64 << trailing_bits) - 1;
self.write(trailing_bits, last & mask);
}
}
pub(crate) fn into_bytes(mut self) -> Vec<u8> {
debug_assert_eq!(self.bits_written % 8, 0);
self.storage.truncate(self.bits_written / 8);
self.storage
}
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}