#![allow(dead_code)]
pub struct BitWriter {
buf: Vec<u8>,
bit_pos: u8,
}
impl BitWriter {
pub fn new() -> Self {
Self {
buf: Vec::new(),
bit_pos: 0,
}
}
pub fn write_bit(&mut self, bit: u8) {
debug_assert!(bit <= 1, "bit must be 0 or 1");
if self.bit_pos == 0 {
self.buf.push(0);
}
let byte = self.buf.last_mut().expect("buf is non-empty after push");
*byte |= (bit & 1) << (7 - self.bit_pos);
self.bit_pos = (self.bit_pos + 1) & 7;
}
pub fn write_bits(&mut self, val: u64, n: u32) {
debug_assert!(n <= 64, "n must be <= 64");
for i in (0..n).rev() {
let bit = ((val >> i) & 1) as u8;
self.write_bit(bit);
}
}
pub fn write_u8(&mut self, v: u8) {
self.write_bits(v as u64, 8);
}
pub fn write_u16(&mut self, v: u16) {
self.write_bits(v as u64, 16);
}
pub fn write_u32(&mut self, v: u32) {
self.write_bits(v as u64, 32);
}
pub fn byte_align(&mut self) {
if self.bit_pos != 0 {
self.bit_pos = 0;
}
}
pub fn into_bytes(self) -> Vec<u8> {
self.buf
}
pub fn as_bytes(&self) -> &[u8] {
&self.buf
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}
pub struct BitReader<'a> {
data: &'a [u8],
byte_pos: usize,
bit_pos: u8,
}
impl<'a> BitReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
byte_pos: 0,
bit_pos: 0,
}
}
pub fn read_bit(&mut self) -> Option<u8> {
if self.byte_pos >= self.data.len() {
return None;
}
let byte = self.data[self.byte_pos];
let bit = (byte >> (7 - self.bit_pos)) & 1;
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bit_pos = 0;
self.byte_pos += 1;
}
Some(bit)
}
pub fn read_bits(&mut self, n: u32) -> Option<u64> {
debug_assert!(n <= 64, "n must be <= 64");
let mut val: u64 = 0;
for _ in 0..n {
let bit = self.read_bit()? as u64;
val = (val << 1) | bit;
}
Some(val)
}
pub fn read_u8(&mut self) -> Option<u8> {
self.read_bits(8).map(|v| v as u8)
}
pub fn read_u16(&mut self) -> Option<u16> {
self.read_bits(16).map(|v| v as u16)
}
pub fn read_u32(&mut self) -> Option<u32> {
self.read_bits(32).map(|v| v as u32)
}
pub fn byte_align(&mut self) {
if self.bit_pos != 0 {
self.bit_pos = 0;
self.byte_pos += 1;
}
}
pub fn bytes_remaining(&self) -> usize {
if self.byte_pos >= self.data.len() {
0
} else {
self.data.len() - self.byte_pos - if self.bit_pos > 0 { 1 } else { 0 }
}
}
pub fn position_bits(&self) -> usize {
self.byte_pos * 8 + self.bit_pos as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_write_read_single_bit() {
let mut w = BitWriter::new();
w.write_bit(1);
w.write_bit(0);
w.write_bit(1);
w.byte_align();
let bytes = w.into_bytes();
assert_eq!(bytes, &[0b10100000]);
}
#[test]
fn test_write_read_bits_round_trip() {
let cases: &[(u64, u32)] = &[
(0, 1),
(1, 1),
(0b101, 3),
(0xFF, 8),
(0x1234, 16),
(0xDEADBEEF, 32),
(0x0102_0304_0506_0708, 64),
(0, 0),
(127, 7),
];
for &(val, n) in cases {
let mut w = BitWriter::new();
w.write_bits(val, n);
w.byte_align();
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
let got = r.read_bits(n).expect("should read back");
assert_eq!(
got, val,
"round-trip failed for val={val:#x} n={n}"
);
}
}
#[test]
fn test_write_u8_read_u8() {
let mut w = BitWriter::new();
w.write_u8(0xAB);
w.write_u8(0xCD);
let bytes = w.into_bytes();
assert_eq!(bytes, &[0xAB, 0xCD]);
let mut r = BitReader::new(&bytes);
assert_eq!(r.read_u8(), Some(0xAB));
assert_eq!(r.read_u8(), Some(0xCD));
assert_eq!(r.read_u8(), None);
}
#[test]
fn test_write_u16_u32_be() {
let mut w = BitWriter::new();
w.write_u16(0x1234);
w.write_u32(0xDEADBEEF);
let bytes = w.into_bytes();
assert_eq!(bytes, &[0x12, 0x34, 0xDE, 0xAD, 0xBE, 0xEF]);
let mut r = BitReader::new(&bytes);
assert_eq!(r.read_u16(), Some(0x1234));
assert_eq!(r.read_u32(), Some(0xDEADBEEF));
}
#[test]
fn test_byte_align_writer_reader() {
let mut w = BitWriter::new();
w.write_bits(0b101, 3);
w.byte_align();
w.write_u8(0xFF);
let bytes = w.into_bytes();
assert_eq!(bytes, &[0b10100000, 0xFF]);
let mut r = BitReader::new(&bytes);
let v = r.read_bits(3).unwrap();
assert_eq!(v, 0b101);
r.byte_align();
assert_eq!(r.position_bits(), 8);
assert_eq!(r.read_u8(), Some(0xFF));
}
#[test]
fn test_position_bits_tracking() {
let data = [0xAB, 0xCD];
let mut r = BitReader::new(&data);
assert_eq!(r.position_bits(), 0);
r.read_bit();
assert_eq!(r.position_bits(), 1);
r.read_bits(7).unwrap();
assert_eq!(r.position_bits(), 8);
r.read_u8().unwrap();
assert_eq!(r.position_bits(), 16);
}
#[test]
fn test_is_empty_len() {
let w = BitWriter::new();
assert!(w.is_empty());
assert_eq!(w.len(), 0);
let mut w = BitWriter::new();
w.write_bit(1);
assert!(!w.is_empty());
assert_eq!(w.len(), 1);
}
}