use super::error::{EncodingError, EncodingResult};
pub struct BitWriter {
buffer: Vec<u8>,
bit_position: u8,
current_byte: u8,
}
impl BitWriter {
pub fn new() -> Self {
Self {
buffer: Vec::new(),
bit_position: 0,
current_byte: 0,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
buffer: Vec::with_capacity(capacity),
bit_position: 0,
current_byte: 0,
}
}
pub fn write_bits(&mut self, value: u64, bits: u8) -> EncodingResult<()> {
if bits == 0 || bits > 64 {
return Err(EncodingError::InvalidFieldValue {
field: "bits",
value: bits.to_string(),
});
}
let masked_value = if bits == 64 {
value
} else {
value & ((1u64 << bits) - 1)
};
let mut remaining_bits = bits;
let mut value_to_write = masked_value;
while remaining_bits > 0 {
let bits_available_in_current_byte = 8 - self.bit_position;
let bits_to_write = remaining_bits.min(bits_available_in_current_byte);
let shift_amount = remaining_bits - bits_to_write;
let bits_value = (value_to_write >> shift_amount) as u8;
let mask = ((1u16 << bits_to_write) - 1) as u8;
self.current_byte |=
(bits_value & mask) << (bits_available_in_current_byte - bits_to_write);
self.bit_position += bits_to_write;
if self.bit_position == 8 {
self.buffer.push(self.current_byte);
self.current_byte = 0;
self.bit_position = 0;
}
remaining_bits -= bits_to_write;
value_to_write &= (1u64 << shift_amount) - 1;
}
Ok(())
}
pub fn write_bit(&mut self, bit: bool) -> EncodingResult<()> {
self.write_bits(if bit { 1 } else { 0 }, 1)
}
pub fn write_bytes(&mut self, bytes: &[u8]) -> EncodingResult<()> {
for &byte in bytes {
self.write_bits(byte as u64, 8)?;
}
Ok(())
}
pub fn align_to_byte(&mut self) -> EncodingResult<()> {
if self.bit_position > 0 {
let padding_bits = 8 - self.bit_position;
self.write_bits(0, padding_bits)?;
}
Ok(())
}
pub fn finish(mut self) -> Vec<u8> {
if self.bit_position > 0 {
self.buffer.push(self.current_byte);
}
self.buffer
}
pub fn len(&self) -> usize {
self.buffer.len() + if self.bit_position > 0 { 1 } else { 0 }
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty() && self.bit_position == 0
}
pub fn bit_position(&self) -> u8 {
self.bit_position
}
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_write_single_byte() {
let mut writer = BitWriter::new();
writer.write_bits(0xAB, 8).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0xAB]);
}
#[test]
fn test_write_bits_across_bytes() {
let mut writer = BitWriter::new();
writer.write_bits(0b101, 3).unwrap(); writer.write_bits(0b11001, 5).unwrap(); writer.write_bits(0b0110, 4).unwrap(); writer.write_bits(0b1111, 4).unwrap(); let buffer = writer.finish();
assert_eq!(buffer, vec![0b10111001, 0b01101111]);
}
#[test]
fn test_write_bit() {
let mut writer = BitWriter::new();
writer.write_bit(true).unwrap();
writer.write_bit(false).unwrap();
writer.write_bit(true).unwrap();
writer.write_bit(true).unwrap();
writer.write_bit(false).unwrap();
writer.write_bit(true).unwrap();
writer.write_bit(false).unwrap();
writer.write_bit(true).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0b10110101]);
}
#[test]
fn test_align_to_byte() {
let mut writer = BitWriter::new();
writer.write_bits(0b101, 3).unwrap();
writer.align_to_byte().unwrap();
writer.write_bits(0xFF, 8).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0b10100000, 0xFF]);
}
#[test]
fn test_write_bytes() {
let mut writer = BitWriter::new();
writer.write_bytes(&[0xAB, 0xCD, 0xEF]).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0xAB, 0xCD, 0xEF]);
}
#[test]
fn test_partial_byte_finish() {
let mut writer = BitWriter::new();
writer.write_bits(0b10110, 5).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0b10110000]);
}
#[test]
fn test_value_masking() {
let mut writer = BitWriter::new();
writer.write_bits(0xFF, 4).unwrap();
let buffer = writer.finish();
assert_eq!(buffer, vec![0b11110000]);
}
#[test]
fn test_invalid_bits() {
let mut writer = BitWriter::new();
assert!(writer.write_bits(0, 0).is_err());
assert!(writer.write_bits(0, 65).is_err());
}
}