use crate::error::{CodecError, CodecResult};
use std::io::{Read, Write};
pub struct BitstreamReader<'a> {
data: &'a [u8],
pos: usize,
bit_pos: u8,
}
impl<'a> BitstreamReader<'a> {
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
pos: 0,
bit_pos: 0,
}
}
#[must_use]
pub fn remaining_bits(&self) -> usize {
let remaining_bytes = self.data.len().saturating_sub(self.pos);
remaining_bytes * 8 - usize::from(self.bit_pos)
}
#[must_use]
pub fn is_byte_aligned(&self) -> bool {
self.bit_pos == 0
}
pub fn byte_align(&mut self) {
if self.bit_pos != 0 {
self.bit_pos = 0;
self.pos += 1;
}
}
pub fn read_bit(&mut self) -> CodecResult<bool> {
if self.pos >= self.data.len() {
return Err(CodecError::InvalidBitstream(
"Unexpected end of bitstream".to_string(),
));
}
let byte = self.data[self.pos];
let bit = (byte >> (7 - self.bit_pos)) & 1;
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bit_pos = 0;
self.pos += 1;
}
Ok(bit != 0)
}
pub fn read_bits(&mut self, n: u8) -> CodecResult<u32> {
if n > 32 {
return Err(CodecError::InvalidBitstream(format!(
"Cannot read more than 32 bits at once, requested {n}"
)));
}
let mut value = 0u32;
for _ in 0..n {
value = (value << 1) | u32::from(self.read_bit()?);
}
Ok(value)
}
pub fn read_signed_bits(&mut self, n: u8) -> CodecResult<i32> {
let value = self.read_bits(n)?;
let sign_bit = 1u32 << (n - 1);
if value & sign_bit != 0 {
Ok((value | (!0u32 << n)) as i32)
} else {
Ok(value as i32)
}
}
pub fn read_byte(&mut self) -> CodecResult<u8> {
self.read_bits(8).map(|v| v as u8)
}
pub fn read_u16(&mut self) -> CodecResult<u16> {
self.read_bits(16).map(|v| v as u16)
}
pub fn read_u32(&mut self) -> CodecResult<u32> {
let high = self.read_bits(16)?;
let low = self.read_bits(16)?;
Ok((high << 16) | low)
}
pub fn read_bytes(&mut self, buf: &mut [u8]) -> CodecResult<()> {
if !self.is_byte_aligned() {
return Err(CodecError::InvalidBitstream(
"Cannot read bytes when not byte-aligned".to_string(),
));
}
let end = self.pos + buf.len();
if end > self.data.len() {
return Err(CodecError::InvalidBitstream(
"Not enough data for read_bytes".to_string(),
));
}
buf.copy_from_slice(&self.data[self.pos..end]);
self.pos = end;
Ok(())
}
pub fn skip_bits(&mut self, n: usize) -> CodecResult<()> {
for _ in 0..n {
self.read_bit()?;
}
Ok(())
}
pub fn peek_bits(&mut self, n: u8) -> CodecResult<u32> {
let saved_pos = self.pos;
let saved_bit_pos = self.bit_pos;
let value = self.read_bits(n)?;
self.pos = saved_pos;
self.bit_pos = saved_bit_pos;
Ok(value)
}
#[must_use]
pub fn position(&self) -> usize {
self.pos
}
#[must_use]
pub fn bit_position(&self) -> u8 {
self.bit_pos
}
}
pub struct BitstreamWriter {
data: Vec<u8>,
bit_pos: u8,
}
impl BitstreamWriter {
#[must_use]
pub fn new() -> Self {
Self {
data: Vec::new(),
bit_pos: 0,
}
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
bit_pos: 0,
}
}
pub fn write_bit(&mut self, bit: bool) {
if self.bit_pos == 0 {
self.data.push(0);
}
if bit {
let last_idx = self.data.len() - 1;
self.data[last_idx] |= 1 << (7 - self.bit_pos);
}
self.bit_pos += 1;
if self.bit_pos == 8 {
self.bit_pos = 0;
}
}
pub fn write_bits(&mut self, value: u32, n: u8) {
for i in (0..n).rev() {
let bit = (value >> i) & 1;
self.write_bit(bit != 0);
}
}
pub fn write_signed_bits(&mut self, value: i32, n: u8) {
let unsigned = if value < 0 {
let mask = (1u32 << n) - 1;
(value as u32) & mask
} else {
value as u32
};
self.write_bits(unsigned, n);
}
pub fn write_byte(&mut self, byte: u8) {
self.write_bits(u32::from(byte), 8);
}
pub fn write_u16(&mut self, value: u16) {
self.write_bits(u32::from(value), 16);
}
pub fn write_u32(&mut self, value: u32) {
self.write_bits(value >> 16, 16);
self.write_bits(value & 0xFFFF, 16);
}
pub fn byte_align(&mut self) {
if self.bit_pos != 0 {
self.bit_pos = 0;
}
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
#[must_use]
pub fn into_vec(self) -> Vec<u8> {
self.data
}
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[must_use]
pub fn is_byte_aligned(&self) -> bool {
self.bit_pos == 0
}
#[must_use]
pub fn bit_position(&self) -> u8 {
self.bit_pos
}
}
impl Default for BitstreamWriter {
fn default() -> Self {
Self::new()
}
}
pub struct ExpGolombReader<'a> {
reader: BitstreamReader<'a>,
}
impl<'a> ExpGolombReader<'a> {
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self {
reader: BitstreamReader::new(data),
}
}
pub fn read_ue(&mut self) -> CodecResult<u32> {
let mut leading_zeros = 0;
while !self.reader.read_bit()? {
leading_zeros += 1;
if leading_zeros > 31 {
return Err(CodecError::InvalidBitstream(
"Too many leading zeros in Exp-Golomb code".to_string(),
));
}
}
if leading_zeros == 0 {
return Ok(0);
}
let value = self.reader.read_bits(leading_zeros)?;
Ok((1u32 << leading_zeros) - 1 + value)
}
pub fn read_se(&mut self) -> CodecResult<i32> {
let code = self.read_ue()?;
if code == 0 {
return Ok(0);
}
let sign = if code & 1 != 0 { 1 } else { -1 };
Ok(sign * ((code + 1) / 2) as i32)
}
#[must_use]
pub fn reader(&mut self) -> &mut BitstreamReader<'a> {
&mut self.reader
}
}
pub struct ExpGolombWriter {
writer: BitstreamWriter,
}
impl ExpGolombWriter {
#[must_use]
pub fn new() -> Self {
Self {
writer: BitstreamWriter::new(),
}
}
pub fn write_ue(&mut self, value: u32) {
let code = value + 1;
let bits = 32 - code.leading_zeros();
let leading_zeros = bits - 1;
for _ in 0..leading_zeros {
self.writer.write_bit(false);
}
self.writer.write_bits(code, bits as u8);
}
pub fn write_se(&mut self, value: i32) {
let code = if value <= 0 {
((-value) * 2) as u32
} else {
(value * 2 - 1) as u32
};
self.write_ue(code);
}
#[must_use]
pub fn writer(&mut self) -> &mut BitstreamWriter {
&mut self.writer
}
#[must_use]
pub fn into_vec(self) -> Vec<u8> {
self.writer.into_vec()
}
}
impl Default for ExpGolombWriter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitstream_reader() {
let data = [0b1010_1100, 0b1111_0000];
let mut reader = BitstreamReader::new(&data);
assert_eq!(reader.read_bit().expect("should succeed"), true);
assert_eq!(reader.read_bit().expect("should succeed"), false);
assert_eq!(reader.read_bits(3).expect("should succeed"), 0b101);
assert_eq!(reader.read_bits(4).expect("should succeed"), 0b1001);
}
#[test]
fn test_bitstream_writer() {
let mut writer = BitstreamWriter::new();
writer.write_bit(true);
writer.write_bit(false);
writer.write_bits(0b101, 3);
writer.write_bits(0b1001, 4);
writer.byte_align();
let data = writer.data();
assert_eq!(data[0], 0b1010_1100);
assert_eq!(data[1], 0b1000_0000);
}
#[test]
fn test_exp_golomb() {
let mut writer = ExpGolombWriter::new();
writer.write_ue(0);
writer.write_ue(1);
writer.write_ue(5);
writer.writer().byte_align();
let data = writer.into_vec();
let mut reader = ExpGolombReader::new(&data);
assert_eq!(reader.read_ue().expect("should succeed"), 0);
assert_eq!(reader.read_ue().expect("should succeed"), 1);
assert_eq!(reader.read_ue().expect("should succeed"), 5);
}
}