#[derive(Debug)]
pub enum BitPackError {
NotByteAligned,
BoundaryReached,
ArrayEndReached,
ExceededBitBoundary,
}
pub struct BitPacker<'a> {
array: &'a mut [u8],
p_byte: usize,
p_bit: usize,
bm_p_byte: usize,
}
impl<'a> BitPacker<'a> {
pub fn new(array: &'a mut [u8]) -> BitPacker {
BitPacker {
array,
p_byte: 0,
p_bit: 0,
bm_p_byte: 0,
}
}
pub fn bookmark(&mut self) {
self.bm_p_byte = self.p_byte;
}
pub fn bookmark_get_from(&self) -> &[u8] {
&self.array[self.bm_p_byte..self.p_byte]
}
pub fn bookmark_get_offset(&self) -> usize {
let offset = if self.p_bit == 0 { 0 } else { 1 };
self.p_byte - self.bm_p_byte + offset
}
pub fn bookmark_write(&mut self, array: &[u8]) {
for (i, value) in array.iter().enumerate() {
self.array[self.bm_p_byte + i] = *value;
}
}
pub fn write_bytes(&mut self, array: &[u8]) {
for value in array {
self.array[self.p_byte] = *value;
self.p_byte += 1;
}
}
pub fn inc_counter_n_bytes(&mut self, n_bytes: usize) -> Result<(), BitPackError> {
if self.p_bit != 0 {
return Err(BitPackError::NotByteAligned);
}
self.p_byte += n_bytes;
Ok(())
}
pub fn word_align(&mut self) {
if self.p_bit != 0 {
self.p_byte += 1;
self.p_bit = 0;
}
if self.p_byte % 2 == 1 {
self.p_byte += 1;
}
}
#[inline(always)]
pub fn write_bits(&mut self, mut value: usize, num_bits: usize) {
let rem_bit = 8 - self.p_bit;
let mask = (1 << num_bits) - 1;
value &= mask;
if num_bits == rem_bit {
self.array[self.p_byte] |= value as u8;
self.p_byte += 1;
self.p_bit = 0;
} else if num_bits < rem_bit {
let shift_l = rem_bit - num_bits;
self.array[self.p_byte] |= (value << shift_l) as u8;
self.p_bit += num_bits;
} else {
let shift_r = num_bits - rem_bit;
self.array[self.p_byte] |= (value >> shift_r) as u8;
self.p_bit = 0;
self.p_byte += 1;
self.write_bits(value, shift_r);
}
}
#[inline(always)]
pub fn write_packed_zeros(&mut self, num_zeros: usize) {
self.p_bit += num_zeros;
while self.p_bit >= 8 {
self.p_bit -= 8;
self.p_byte += 1;
}
}
pub fn as_bytes(&self) -> &[u8] {
&self.array[0..self.p_byte]
}
}
#[cfg(test)]
mod tests {
use crate::bitpacker::BitPacker;
#[test]
fn test_write_packed_bits() {
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 1;
bp.write_bits(0x03, 2);
assert_eq!(1, bp.p_byte);
assert_eq!(3, bp.p_bit);
assert_eq!(&[0x00, 0x60, 0x00], bp.array);
let inp_arr: &mut [u8] = &mut [0xff, 0x80, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 1;
bp.write_bits(0x03, 2);
assert_eq!(1, bp.p_byte);
assert_eq!(3, bp.p_bit);
assert_eq!(&[0xff, 0xE0, 0x00], bp.array);
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 5;
bp.write_bits(0x1ff, 9);
assert_eq!(2, bp.p_byte);
assert_eq!(6, bp.p_bit);
assert_eq!(&[0x00, 0x07, 0xfc], bp.array);
let inp_arr: &mut [u8] = &mut [0xff, 0xfc, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 5;
bp.write_bits(0x1ff, 9);
assert_eq!(2, bp.p_byte);
assert_eq!(6, bp.p_bit);
assert_eq!(&[0xff, 0xff, 0xfc], bp.array);
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 0;
bp.p_bit = 6;
bp.write_bits(0x1f27b, 17);
assert_eq!(2, bp.p_byte);
assert_eq!(7, bp.p_bit);
assert_eq!(&[0x03, 0xe4, 0xf6], bp.array);
let inp_arr: &mut [u8] = &mut [0xfe, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 0;
bp.p_bit = 6;
bp.write_bits(0x1f27b, 17);
assert_eq!(2, bp.p_byte);
assert_eq!(7, bp.p_bit);
assert_eq!(&[0xff, 0xe4, 0xf6], bp.array);
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 4;
bp.write_bits(0x09, 4);
assert_eq!(2, bp.p_byte);
assert_eq!(0, bp.p_bit);
assert_eq!(&[0x00, 0x09, 0x00], bp.array);
let inp_arr: &mut [u8] = &mut [0xf0, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 0;
bp.p_bit = 4;
bp.write_bits(0xffffbe81, 16);
assert_eq!(2, bp.p_byte);
assert_eq!(4, bp.p_bit);
assert_eq!(&[0xfb, 0xe8, 0x10], bp.array);
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 1;
bp.write_bits(0xfffffffc, 6);
assert_eq!(1, bp.p_byte);
assert_eq!(7, bp.p_bit);
assert_eq!(&[0x00, 0x78, 0x00], bp.array);
let inp_arr: &mut [u8] = &mut [0x00, 0x00, 0x00];
let mut bp = BitPacker::new(inp_arr);
bp.p_byte = 1;
bp.p_bit = 2;
bp.write_bits(0xfffffffc, 6);
assert_eq!(2, bp.p_byte);
assert_eq!(0, bp.p_bit);
assert_eq!(&[0x00, 0x3c, 0x00], bp.array);
}
}