use crate::compliance::iab_tcf::{BitField, Error, Result};
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<bool> {
if self.byte_pos >= self.data.len() {
return Err(Error::EndOfData);
}
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;
}
Ok(bit == 1)
}
pub fn read_bits(&mut self, num_bits: u8) -> Result<u64> {
if num_bits > 64 {
return Err(Error::TooManyBits(num_bits));
}
if num_bits == 0 {
return Ok(0);
}
let mut value = 0u64;
for _ in 0..num_bits {
value = (value << 1) | u64::from(self.read_bit()?);
}
Ok(value)
}
pub fn read_bitfield(&mut self, size: usize) -> Result<BitField> {
let mut field = BitField::new(size);
for i in 0..size {
field.set(i, self.read_bit()?);
}
Ok(field)
}
#[must_use]
pub fn position(&self) -> (usize, u8) {
(self.byte_pos, self.bit_pos)
}
#[must_use]
pub fn remaining_bits(&self) -> usize {
let total_bits = self.data.len() * 8;
let consumed_bits = self.byte_pos * 8 + self.bit_pos as usize;
total_bits.saturating_sub(consumed_bits)
}
#[must_use]
pub fn has_remaining(&self) -> bool {
self.remaining_bits() > 0
}
pub fn reset(&mut self) {
self.byte_pos = 0;
self.bit_pos = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_read_single_bits() -> Result<()> {
let data = vec![0b1011_0100];
let mut reader = BitReader::new(&data);
assert!(reader.read_bit()?); assert!(!(reader.read_bit()?)); assert!(reader.read_bit()?); assert!(reader.read_bit()?); assert!(!(reader.read_bit()?)); assert!(reader.read_bit()?); assert!(!(reader.read_bit()?)); assert!(!(reader.read_bit()?));
Ok(())
}
#[test]
fn test_read_multiple_bits() -> Result<()> {
let data = vec![0b1011_0100, 0b1100_1010];
let mut reader = BitReader::new(&data);
assert_eq!(reader.read_bits(4)?, 0b1011); assert_eq!(reader.read_bits(8)?, 0b0100_1100); assert_eq!(reader.read_bits(4)?, 0b1010);
Ok(())
}
#[test]
fn test_read_across_byte_boundary() -> Result<()> {
let data = vec![0b1111_1111, 0b0000_0000];
let mut reader = BitReader::new(&data);
reader.read_bits(6)?; let value = reader.read_bits(4)?; assert_eq!(value, 0b1100);
Ok(())
}
#[test]
fn test_read_bitfield() -> Result<()> {
let data = vec![0b1111_0000];
let mut reader = BitReader::new(&data);
let field = reader.read_bitfield(8)?;
assert!(field.get(0));
assert!(field.get(1));
assert!(field.get(2));
assert!(field.get(3));
assert!(!field.get(4));
assert!(!field.get(5));
assert!(!field.get(6));
assert!(!field.get(7));
Ok(())
}
#[test]
fn test_end_of_data_error() {
let data = vec![0b1011_0100];
let mut reader = BitReader::new(&data);
reader.read_bits(8).unwrap();
assert!(matches!(reader.read_bit(), Err(Error::EndOfData)));
}
#[test]
fn test_too_many_bits_error() {
let data = vec![0xFF; 10];
let mut reader = BitReader::new(&data);
assert!(matches!(reader.read_bits(65), Err(Error::TooManyBits(65))));
}
#[test]
fn test_remaining_bits() -> Result<()> {
let data = vec![0xFF, 0xFF]; let mut reader = BitReader::new(&data);
assert_eq!(reader.remaining_bits(), 16);
reader.read_bits(5)?;
assert_eq!(reader.remaining_bits(), 11);
reader.read_bits(11)?;
assert_eq!(reader.remaining_bits(), 0);
assert!(!reader.has_remaining());
Ok(())
}
#[test]
fn test_position() -> Result<()> {
let data = vec![0xFF, 0xFF];
let mut reader = BitReader::new(&data);
reader.read_bits(5)?;
let (byte_pos, bit_pos) = reader.position();
assert_eq!(byte_pos, 0);
assert_eq!(bit_pos, 5);
reader.read_bits(4)?;
let (byte_pos, bit_pos) = reader.position();
assert_eq!(byte_pos, 1);
assert_eq!(bit_pos, 1);
Ok(())
}
#[test]
fn test_reset() -> Result<()> {
let data = vec![0xFF];
let mut reader = BitReader::new(&data);
reader.read_bits(5)?;
assert_ne!(reader.remaining_bits(), 8);
reader.reset();
assert_eq!(reader.remaining_bits(), 8);
let (byte_pos, bit_pos) = reader.position();
assert_eq!(byte_pos, 0);
assert_eq!(bit_pos, 0);
Ok(())
}
#[test]
fn test_read_zero_bits() -> Result<()> {
let data = vec![0xFF];
let mut reader = BitReader::new(&data);
let value = reader.read_bits(0)?;
assert_eq!(value, 0);
assert_eq!(reader.remaining_bits(), 8);
Ok(())
}
}