use crate::{
error::SafebitStreamError,
util::Endianess,
word::{TypeCast, Word},
word_read::WordRead,
};
use core::marker::PhantomData;
pub struct Bitstream<'a, DW, E, R, End>
where
DW: Word,
R: WordRead<DW, E, End>,
End: Endianess,
{
reader: &'a mut R,
buf: DW,
buf_consumed_bits: usize,
phantom1: PhantomData<&'a E>,
phantom2: PhantomData<&'a End>,
}
impl<'a, DW, E, WR, End> Bitstream<'a, DW, E, WR, End>
where
DW: Word,
WR: WordRead<DW, E, End>,
End: Endianess,
{
pub fn new(reader: &'a mut WR) -> Self {
Self {
reader,
buf: DW::ZERO,
buf_consumed_bits: DW::BIT_LEN,
phantom1: PhantomData,
phantom2: PhantomData,
}
}
pub fn read<OW>(&mut self, bit_len: usize) -> Result<OW, SafebitStreamError<E>>
where
OW: Word,
DW: TypeCast<OW>,
SafebitStreamError<E>: From<E>,
{
if bit_len == 0 {
return Err(SafebitStreamError::InvalidLength { bit_len });
}
if bit_len > OW::BIT_LEN {
return Err(SafebitStreamError::InvalidLength { bit_len });
}
let mut output = OW::ZERO;
let mut remaining_bit_len = bit_len;
while remaining_bit_len > 0 {
if self.buf_consumed_bits == DW::BIT_LEN {
self.buf = self.reader.read()?;
self.buf_consumed_bits = 0;
}
let buf_remaining_bits = DW::BIT_LEN - self.buf_consumed_bits;
let subslice_len = buf_remaining_bits.min(remaining_bit_len);
let surplus_len = DW::BIT_LEN - self.buf_consumed_bits - subslice_len;
let left_shifted = self.buf << self.buf_consumed_bits;
let subslice = left_shifted >> (self.buf_consumed_bits + surplus_len);
let sublice_ow: OW = subslice.typecast();
remaining_bit_len -= subslice_len;
self.buf_consumed_bits += subslice_len;
output |= sublice_ow << remaining_bit_len;
}
if OW::IS_SIGNED {
let sign_mask = OW::ONE << (bit_len - 1);
if output & sign_mask != OW::ZERO {
let ones: OW::UnsignedType = !OW::UnsignedType::ZERO;
let mask = (ones >> bit_len) << bit_len; output |= mask.typecast();
}
}
Ok(output)
}
}
#[cfg(test)]
mod tests {
use std::{fs::File, io::BufReader};
extern crate std;
use crate::{bitstream::Bitstream, util::LittleEndian};
#[test]
fn test_safe_bit_stream() {
let f = File::open("Cargo.toml").unwrap();
let mut buf_reader = BufReader::new(f);
let mut stream: Bitstream<u16, _, _, LittleEndian> = Bitstream::new(&mut buf_reader);
let w1: u16 = stream.read(8).unwrap();
assert_eq!(w1, 0x70);
let w2: u16 = stream.read(8).unwrap();
assert_eq!(w2, 0x5b);
}
}