use std::mem::size_of;
use std::ops::BitOrAssign;
use num_traits::{Float, PrimInt};
use crate::endianness::Endianness;
use crate::is_signed::IsSigned;
use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::BitBuffer;
use crate::{BitRead, BitReadSized, ReadError, Result};
#[derive(Debug)]
pub struct BitStream<E>
where
E: Endianness,
{
buffer: BitBuffer<E>,
start_pos: usize,
pos: usize,
bit_len: usize,
}
impl<E> BitStream<E>
where
E: Endianness,
{
pub fn new(buffer: BitBuffer<E>) -> Self {
BitStream {
start_pos: 0,
pos: 0,
bit_len: buffer.bit_len(),
buffer,
}
}
pub fn read_bool(&mut self) -> Result<bool> {
let result = self.buffer.read_bool(self.pos);
if result.is_ok() {
self.pos += 1;
}
result
}
pub fn read_int<T>(&mut self, count: usize) -> Result<T>
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let result = self.buffer.read_int(self.pos, count);
if result.is_ok() {
self.pos += count;
}
result
}
pub fn read_float<T>(&mut self) -> Result<T>
where
T: Float + UncheckedPrimitiveFloat,
{
let count = size_of::<T>() * 8;
let result = self.buffer.read_float(self.pos);
if result.is_ok() {
self.pos += count;
}
result
}
pub fn read_bytes(&mut self, byte_count: usize) -> Result<Vec<u8>> {
let count = byte_count * 8;
let result = self.buffer.read_bytes(self.pos, byte_count);
if result.is_ok() {
self.pos += count;
}
result
}
pub fn read_string(&mut self, byte_len: Option<usize>) -> Result<String> {
let result = self.buffer.read_string(self.pos, byte_len)?;
let read = match byte_len {
Some(len) => len * 8,
None => (result.len() + 1) * 8,
};
self.pos += read;
Ok(result)
}
pub fn read_bits(&mut self, count: usize) -> Result<Self> {
let result = BitStream {
buffer: self.buffer.get_sub_buffer(self.pos + count)?,
start_pos: self.pos,
pos: self.pos,
bit_len: count,
};
self.pos += count;
Ok(result)
}
pub fn skip(&mut self, count: usize) -> Result<()> {
self.pos += count;
Ok(())
}
pub fn set_pos(&mut self, pos: usize) -> Result<()> {
if pos > self.bit_len {
return Err(ReadError::IndexOutOfBounds {
pos,
size: self.bit_len,
});
}
self.pos = pos + self.start_pos;
Ok(())
}
pub fn bit_len(&self) -> usize {
self.bit_len
}
pub fn pos(&self) -> usize {
self.pos - self.start_pos
}
pub fn bits_left(&self) -> usize {
self.bit_len - self.pos()
}
#[inline]
pub fn read<T: BitRead<E>>(&mut self) -> Result<T> {
T::read(self)
}
#[inline]
pub fn read_sized<T: BitReadSized<E>>(&mut self, size: usize) -> Result<T> {
T::read(self, size)
}
}
impl<E: Endianness> Clone for BitStream<E> {
fn clone(&self) -> Self {
BitStream {
buffer: self.buffer.clone(),
start_pos: self.pos,
pos: self.pos,
bit_len: self.bit_len,
}
}
}
impl<E: Endianness> From<BitBuffer<E>> for BitStream<E> {
fn from(buffer: BitBuffer<E>) -> Self {
BitStream::new(buffer)
}
}
impl<E: Endianness> From<Vec<u8>> for BitStream<E> {
fn from(bytes: Vec<u8>) -> Self {
BitStream::new(BitBuffer::from(bytes))
}
}