use super::types::ApvError;
#[derive(Clone, Debug)]
pub struct BitWriter {
buf: Vec<u8>,
current_byte: u8,
bit_pos: u8,
}
impl BitWriter {
#[must_use]
pub fn new(capacity: usize) -> Self {
Self {
buf: Vec::with_capacity(capacity),
current_byte: 0,
bit_pos: 0,
}
}
pub fn write_bit(&mut self, bit: u8) {
self.current_byte = (self.current_byte << 1) | (bit & 1);
self.bit_pos += 1;
if self.bit_pos == 8 {
self.buf.push(self.current_byte);
self.current_byte = 0;
self.bit_pos = 0;
}
}
pub fn write_bits(&mut self, value: u32, n: u8) {
for i in (0..n).rev() {
self.write_bit(((value >> i) & 1) as u8);
}
}
#[must_use]
pub fn finish(mut self) -> Vec<u8> {
if self.bit_pos > 0 {
self.current_byte <<= 8 - self.bit_pos;
self.buf.push(self.current_byte);
}
self.buf
}
#[must_use]
pub fn bit_count(&self) -> usize {
self.buf.len() * 8 + self.bit_pos as usize
}
}
#[derive(Clone, Debug)]
pub struct BitReader<'a> {
data: &'a [u8],
byte_pos: usize,
bit_pos: u8,
}
impl<'a> BitReader<'a> {
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
byte_pos: 0,
bit_pos: 0,
}
}
pub fn read_bit(&mut self) -> Result<u8, ApvError> {
if self.byte_pos >= self.data.len() {
return Err(ApvError::InvalidBitstream(
"unexpected end of bitstream".to_string(),
));
}
let bit = (self.data[self.byte_pos] >> (7 - self.bit_pos)) & 1;
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bit_pos = 0;
self.byte_pos += 1;
}
Ok(bit)
}
pub fn read_bits(&mut self, n: u8) -> Result<u32, ApvError> {
let mut value = 0u32;
for _ in 0..n {
value = (value << 1) | self.read_bit()? as u32;
}
Ok(value)
}
#[must_use]
pub fn bits_read(&self) -> usize {
self.byte_pos * 8 + self.bit_pos as usize
}
#[must_use]
pub fn has_more(&self) -> bool {
self.byte_pos < self.data.len()
}
}
pub fn exp_golomb_encode(writer: &mut BitWriter, value: u32) {
let xp1 = value + 1;
let n_bits = 32 - xp1.leading_zeros(); for _ in 0..(n_bits - 1) {
writer.write_bit(0);
}
writer.write_bits(xp1, n_bits as u8);
}
pub fn exp_golomb_decode(reader: &mut BitReader<'_>) -> Result<u32, ApvError> {
let mut leading_zeros: u32 = 0;
loop {
let bit = reader.read_bit()?;
if bit == 0 {
leading_zeros += 1;
if leading_zeros > 31 {
return Err(ApvError::InvalidBitstream(
"exp-Golomb code too long".to_string(),
));
}
} else {
break;
}
}
let remaining = reader.read_bits(leading_zeros as u8)?;
Ok((1 << leading_zeros) - 1 + remaining)
}
#[must_use]
pub fn zigzag_encode_signed(value: i32) -> u32 {
((value << 1) ^ (value >> 31)) as u32
}
#[must_use]
pub fn zigzag_decode_signed(value: u32) -> i32 {
((value >> 1) as i32) ^ (-((value & 1) as i32))
}
pub fn signed_exp_golomb_encode(writer: &mut BitWriter, value: i32) {
let mapped = zigzag_encode_signed(value);
exp_golomb_encode(writer, mapped);
}
pub fn signed_exp_golomb_decode(reader: &mut BitReader<'_>) -> Result<i32, ApvError> {
let mapped = exp_golomb_decode(reader)?;
Ok(zigzag_decode_signed(mapped))
}
const EOB_RUN: u32 = 0;
const EOB_VALUE: i32 = 0;
pub fn encode_block_coefficients(writer: &mut BitWriter, coeffs: &[i32; 64]) {
let mut i = 0;
while i < 64 {
let mut zero_run: u32 = 0;
while i < 64 && coeffs[i] == 0 {
zero_run += 1;
i += 1;
}
if i >= 64 {
exp_golomb_encode(writer, EOB_RUN);
signed_exp_golomb_encode(writer, EOB_VALUE);
return;
}
exp_golomb_encode(writer, zero_run);
signed_exp_golomb_encode(writer, coeffs[i]);
i += 1;
}
exp_golomb_encode(writer, EOB_RUN);
signed_exp_golomb_encode(writer, EOB_VALUE);
}
pub fn decode_block_coefficients(reader: &mut BitReader<'_>) -> Result<[i32; 64], ApvError> {
let mut coeffs = [0i32; 64];
let mut i: usize = 0;
loop {
if i >= 64 {
break;
}
let zero_run = exp_golomb_decode(reader)?;
let value = signed_exp_golomb_decode(reader)?;
if zero_run == EOB_RUN && value == EOB_VALUE {
break;
}
let new_pos = i + zero_run as usize;
if new_pos >= 64 {
return Err(ApvError::InvalidBitstream(format!(
"zero run {zero_run} at position {i} overflows block"
)));
}
i = new_pos;
if i >= 64 {
return Err(ApvError::InvalidBitstream(
"coefficient position overflows block".to_string(),
));
}
coeffs[i] = value;
i += 1;
}
Ok(coeffs)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitwriter_single_bits() {
let mut w = BitWriter::new(16);
w.write_bit(1);
w.write_bit(0);
w.write_bit(1);
w.write_bit(1);
w.write_bit(0);
w.write_bit(0);
w.write_bit(1);
w.write_bit(0);
let data = w.finish();
assert_eq!(data, vec![0b1011_0010]);
}
#[test]
fn test_bitwriter_partial_byte() {
let mut w = BitWriter::new(16);
w.write_bit(1);
w.write_bit(1);
w.write_bit(0);
let data = w.finish();
assert_eq!(data, vec![0b1100_0000]);
}
#[test]
fn test_bitwriter_write_bits() {
let mut w = BitWriter::new(16);
w.write_bits(0b1010, 4);
w.write_bits(0b1100, 4);
let data = w.finish();
assert_eq!(data, vec![0b1010_1100]);
}
#[test]
fn test_bitwriter_bit_count() {
let mut w = BitWriter::new(16);
assert_eq!(w.bit_count(), 0);
w.write_bits(0xFF, 8);
assert_eq!(w.bit_count(), 8);
w.write_bit(1);
assert_eq!(w.bit_count(), 9);
}
#[test]
fn test_bitreader_single_bits() {
let data = vec![0b1011_0010];
let mut r = BitReader::new(&data);
assert_eq!(r.read_bit().expect("bit"), 1);
assert_eq!(r.read_bit().expect("bit"), 0);
assert_eq!(r.read_bit().expect("bit"), 1);
assert_eq!(r.read_bit().expect("bit"), 1);
assert_eq!(r.read_bit().expect("bit"), 0);
assert_eq!(r.read_bit().expect("bit"), 0);
assert_eq!(r.read_bit().expect("bit"), 1);
assert_eq!(r.read_bit().expect("bit"), 0);
}
#[test]
fn test_bitreader_read_bits() {
let data = vec![0b1010_1100];
let mut r = BitReader::new(&data);
assert_eq!(r.read_bits(4).expect("bits"), 0b1010);
assert_eq!(r.read_bits(4).expect("bits"), 0b1100);
}
#[test]
fn test_bitreader_exhausted() {
let data = vec![0xFF];
let mut r = BitReader::new(&data);
for _ in 0..8 {
r.read_bit().expect("bit");
}
assert!(r.read_bit().is_err());
}
#[test]
fn test_bitwriter_reader_roundtrip() {
let mut w = BitWriter::new(64);
w.write_bits(0xDEAD, 16);
w.write_bits(0b101, 3);
w.write_bits(0b11, 2);
let data = w.finish();
let mut r = BitReader::new(&data);
assert_eq!(r.read_bits(16).expect("bits"), 0xDEAD);
assert_eq!(r.read_bits(3).expect("bits"), 0b101);
assert_eq!(r.read_bits(2).expect("bits"), 0b11);
}
#[test]
fn test_exp_golomb_encode_decode_small_values() {
for value in 0..=20u32 {
let mut w = BitWriter::new(16);
exp_golomb_encode(&mut w, value);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = exp_golomb_decode(&mut r).expect("decode");
assert_eq!(decoded, value, "exp-Golomb roundtrip failed for {value}");
}
}
#[test]
fn test_exp_golomb_encode_decode_large_values() {
for &value in &[100u32, 255, 1000, 10000, 65535] {
let mut w = BitWriter::new(16);
exp_golomb_encode(&mut w, value);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = exp_golomb_decode(&mut r).expect("decode");
assert_eq!(decoded, value, "exp-Golomb roundtrip failed for {value}");
}
}
#[test]
fn test_exp_golomb_zero() {
let mut w = BitWriter::new(16);
exp_golomb_encode(&mut w, 0);
let data = w.finish();
assert_eq!(data.len(), 1);
assert_eq!(data[0] & 0x80, 0x80); }
#[test]
fn test_exp_golomb_one() {
let mut w = BitWriter::new(16);
exp_golomb_encode(&mut w, 1);
let data = w.finish();
let mut r = BitReader::new(&data);
assert_eq!(r.read_bit().expect("bit"), 0); assert_eq!(r.read_bit().expect("bit"), 1); assert_eq!(r.read_bit().expect("bit"), 0); }
#[test]
fn test_exp_golomb_multiple_values() {
let values = [0u32, 5, 100, 3, 0, 255, 1];
let mut w = BitWriter::new(128);
for &v in &values {
exp_golomb_encode(&mut w, v);
}
let data = w.finish();
let mut r = BitReader::new(&data);
for &expected in &values {
let decoded = exp_golomb_decode(&mut r).expect("decode");
assert_eq!(decoded, expected);
}
}
#[test]
fn test_zigzag_mapping() {
assert_eq!(zigzag_encode_signed(0), 0);
assert_eq!(zigzag_encode_signed(-1), 1);
assert_eq!(zigzag_encode_signed(1), 2);
assert_eq!(zigzag_encode_signed(-2), 3);
assert_eq!(zigzag_encode_signed(2), 4);
}
#[test]
fn test_zigzag_roundtrip() {
for v in -1000..=1000 {
let encoded = zigzag_encode_signed(v);
let decoded = zigzag_decode_signed(encoded);
assert_eq!(decoded, v, "zigzag roundtrip failed for {v}");
}
}
#[test]
fn test_signed_exp_golomb_roundtrip() {
for value in -50..=50 {
let mut w = BitWriter::new(16);
signed_exp_golomb_encode(&mut w, value);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = signed_exp_golomb_decode(&mut r).expect("decode");
assert_eq!(
decoded, value,
"signed exp-Golomb roundtrip failed for {value}"
);
}
}
#[test]
fn test_signed_exp_golomb_negative() {
let mut w = BitWriter::new(16);
signed_exp_golomb_encode(&mut w, -42);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = signed_exp_golomb_decode(&mut r).expect("decode");
assert_eq!(decoded, -42);
}
#[test]
fn test_encode_decode_all_zeros() {
let coeffs = [0i32; 64];
let mut w = BitWriter::new(64);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_dc_only() {
let mut coeffs = [0i32; 64];
coeffs[0] = 42;
let mut w = BitWriter::new(64);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_sparse_block() {
let mut coeffs = [0i32; 64];
coeffs[0] = 100;
coeffs[5] = -20;
coeffs[10] = 3;
coeffs[63] = -1;
let mut w = BitWriter::new(128);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_dense_block() {
let mut coeffs = [0i32; 64];
for i in 0..64 {
coeffs[i] = (i as i32 - 32) * 2;
}
let mut w = BitWriter::new(256);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_negative_values() {
let mut coeffs = [0i32; 64];
coeffs[0] = -500;
coeffs[1] = 300;
coeffs[2] = -1;
coeffs[3] = 1;
let mut w = BitWriter::new(128);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_all_nonzero() {
let mut coeffs = [0i32; 64];
for i in 0..64 {
coeffs[i] = if i % 2 == 0 {
(i as i32) + 1
} else {
-(i as i32) - 1
};
}
let mut w = BitWriter::new(512);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
#[test]
fn test_encode_decode_multiple_blocks() {
let block1 = {
let mut c = [0i32; 64];
c[0] = 100;
c[1] = -50;
c
};
let block2 = {
let mut c = [0i32; 64];
c[0] = -200;
c[10] = 30;
c[63] = 1;
c
};
let mut w = BitWriter::new(256);
encode_block_coefficients(&mut w, &block1);
encode_block_coefficients(&mut w, &block2);
let data = w.finish();
let mut r = BitReader::new(&data);
let dec1 = decode_block_coefficients(&mut r).expect("decode block 1");
let dec2 = decode_block_coefficients(&mut r).expect("decode block 2");
assert_eq!(dec1, block1);
assert_eq!(dec2, block2);
}
#[test]
fn test_bitreader_bits_read() {
let data = vec![0xFF, 0x00];
let mut r = BitReader::new(&data);
assert_eq!(r.bits_read(), 0);
r.read_bits(4).expect("bits");
assert_eq!(r.bits_read(), 4);
r.read_bits(8).expect("bits");
assert_eq!(r.bits_read(), 12);
}
#[test]
fn test_bitreader_has_more() {
let data = vec![0xFF];
let mut r = BitReader::new(&data);
assert!(r.has_more());
r.read_bits(8).expect("bits");
assert!(!r.has_more());
}
#[test]
fn test_encode_efficiency() {
let zeros = [0i32; 64];
let mut w = BitWriter::new(64);
encode_block_coefficients(&mut w, &zeros);
let zero_data = w.finish();
let mut dense = [0i32; 64];
for i in 0..64 {
dense[i] = (i as i32) * 10;
}
let mut w2 = BitWriter::new(256);
encode_block_coefficients(&mut w2, &dense);
let dense_data = w2.finish();
assert!(
dense_data.len() > zero_data.len(),
"Dense block should produce more data than all-zeros"
);
}
#[test]
fn test_encode_large_coefficient() {
let mut coeffs = [0i32; 64];
coeffs[0] = 10000;
coeffs[1] = -10000;
let mut w = BitWriter::new(128);
encode_block_coefficients(&mut w, &coeffs);
let data = w.finish();
let mut r = BitReader::new(&data);
let decoded = decode_block_coefficients(&mut r).expect("decode");
assert_eq!(decoded, coeffs);
}
}