use std::cmp::min;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::{size_of, transmute};
use std::ops::BitOrAssign;
use std::rc::Rc;
use num_traits::{Float, PrimInt};
use crate::endianness::Endianness;
use crate::is_signed::IsSigned;
use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::{ReadError, Result};
const USIZE_SIZE: usize = size_of::<usize>();
pub struct BitBuffer<E>
where
E: Endianness,
{
bytes: Rc<Vec<u8>>,
bit_len: usize,
byte_len: usize,
endianness: PhantomData<E>,
}
impl<E> BitBuffer<E>
where
E: Endianness,
{
pub fn new(bytes: Vec<u8>, _endianness: E) -> Self {
let byte_len = bytes.len();
BitBuffer {
bytes: Rc::new(bytes),
byte_len,
bit_len: byte_len * 8,
endianness: PhantomData,
}
}
}
impl<E> BitBuffer<E>
where
E: Endianness,
{
pub fn bit_len(&self) -> usize {
self.bit_len
}
pub fn byte_len(&self) -> usize {
self.byte_len
}
fn read_usize(&self, position: usize, count: usize) -> usize {
let byte_index = position / 8;
let bit_offset = position & 7;
let usize_bit_size = size_of::<usize>() * 8;
let raw_container: &usize = unsafe {
let ptr = self.bytes.as_ptr().add(byte_index);
transmute(ptr)
};
let container = if E::is_le() {
usize::from_le(*raw_container)
} else {
usize::from_be(*raw_container)
};
let shifted = if E::is_le() {
container >> bit_offset
} else {
container >> (usize_bit_size - bit_offset - count)
};
let mask = !(usize::max_value() << count);
shifted & mask
}
pub fn read_bool(&self, position: usize) -> Result<bool> {
let byte_index = position / 8;
let bit_offset = position & 7;
if position >= self.bit_len {
return Err(ReadError::NotEnoughData {
requested: 1,
bits_left: self.bit_len - position,
});
}
let byte = self.bytes[byte_index];
let shifted = byte >> bit_offset;
Ok(shifted & 1u8 == 1)
}
#[inline]
pub fn read_int<T>(&self, position: usize, count: usize) -> Result<T>
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let type_bit_size = size_of::<T>() * 8;
let usize_bit_size = size_of::<usize>() * 8;
if type_bit_size < count {
return Err(ReadError::TooManyBits {
requested: count,
max: type_bit_size,
});
}
if position + count > self.bit_len {
if position > self.bit_len {
return Err(ReadError::IndexOutOfBounds {
pos: position,
size: self.bit_len,
});
} else {
return Err(ReadError::NotEnoughData {
requested: count,
bits_left: self.bit_len - position,
});
}
}
let bit_offset = position & 7;
let fit_usize = count + bit_offset < usize_bit_size;
let value = if fit_usize {
self.read_fit_usize(position, count)
} else {
self.read_no_fit_usize(position, count)
};
Ok(if count == type_bit_size && fit_usize {
value
} else {
self.make_signed(value, count)
})
}
#[inline]
fn read_fit_usize<T>(&self, position: usize, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let type_bit_size = size_of::<T>() * 8;
let raw = self.read_usize(position, count);
let max_signed_value = (1 << (type_bit_size - 1)) - 1;
if T::is_signed() && raw > max_signed_value {
T::zero() - T::from_unchecked(raw & max_signed_value)
} else {
T::from_unchecked(raw)
}
}
fn read_no_fit_usize<T>(&self, position: usize, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let mut left_to_read = count;
let mut acc = T::zero();
let max_read = (size_of::<usize>() - 1) * 8;
let mut read_pos = position;
let mut bit_offset = 0;
while left_to_read > 0 {
let bits_left = self.bit_len - read_pos;
let read = min(min(left_to_read, max_read), bits_left);
let data = T::from_unchecked(self.read_usize(read_pos, read));
if E::is_le() {
acc |= data << bit_offset;
} else {
acc = acc << read;
acc |= data;
}
bit_offset += read;
read_pos += read;
left_to_read -= read;
}
acc
}
fn make_signed<T>(&self, value: T, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
if T::is_signed() {
let sign_bit = value >> (count - 1) & T::one();
let absolute_value = value & !(T::max_value() << (count - 1));
let sign = T::one() - sign_bit - sign_bit;
absolute_value * sign
} else {
value
}
}
pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> {
if position + byte_count * 8 > self.bit_len {
if position > self.bit_len {
return Err(ReadError::IndexOutOfBounds {
pos: position,
size: self.bit_len,
});
} else {
return Err(ReadError::NotEnoughData {
requested: byte_count * 8,
bits_left: self.bit_len - position,
});
}
}
let mut data = Vec::with_capacity(byte_count);
let mut byte_left = byte_count;
let max_read = size_of::<usize>() - 1;
let mut read_pos = position;
while byte_left > 0 {
let read = min(byte_left, max_read);
let raw_bytes = self.read_usize(read_pos, read * 8);
let bytes: [u8; USIZE_SIZE] = if E::is_le() {
raw_bytes.to_le_bytes()
} else {
raw_bytes.to_be_bytes()
};
let usable_bytes = if E::is_le() {
&bytes[0..read]
} else {
&bytes[USIZE_SIZE - read..USIZE_SIZE]
};
data.extend_from_slice(usable_bytes);
byte_left -= read;
read_pos += read * 8;
}
Ok(data)
}
pub fn read_string(&self, position: usize, byte_len: Option<usize>) -> Result<String> {
let bytes = self.read_string_bytes(position, byte_len)?;
let raw_string = String::from_utf8(bytes)?;
Ok(raw_string.trim_end_matches(char::from(0)).to_owned())
}
fn read_string_bytes(&self, position: usize, byte_len: Option<usize>) -> Result<Vec<u8>> {
match byte_len {
Some(len) => return self.read_bytes(position, len),
None => {
let mut acc = Vec::with_capacity(25);
let mut pos = position;
loop {
let read = min((USIZE_SIZE - 1) * 8, self.bit_len - pos);
let raw_bytes = self.read_usize(pos, read);
let bytes: [u8; USIZE_SIZE] = if E::is_le() {
raw_bytes.to_le_bytes()
} else {
raw_bytes.to_be_bytes()
};
for i in 0..(USIZE_SIZE - 1) {
let byte = if E::is_le() { bytes[i] } else { bytes[1 + i] };
if byte == 0 {
return Ok(acc);
}
acc.push(byte);
}
pos += read;
}
}
};
}
pub fn read_float<T>(&self, position: usize) -> Result<T>
where
T: Float + UncheckedPrimitiveFloat,
{
let type_bit_size = size_of::<T>() * 8;
if position + type_bit_size > self.bit_len {
if position > self.bit_len {
return Err(ReadError::IndexOutOfBounds {
pos: position,
size: self.bit_len,
});
} else {
return Err(ReadError::NotEnoughData {
requested: size_of::<T>() * 8,
bits_left: self.bit_len - position,
});
}
}
if size_of::<T>() == 4 {
let int = if size_of::<T>() < USIZE_SIZE {
self.read_fit_usize::<u32>(position, 32)
} else {
self.read_no_fit_usize::<u32>(position, 32)
};
Ok(T::from_f32_unchecked(f32::from_bits(int)))
} else {
let int = self.read_no_fit_usize::<u64>(position, 64);
Ok(T::from_f64_unchecked(f64::from_bits(int)))
}
}
pub fn get_sub_buffer(&self, bit_len: usize) -> Result<Self> {
if bit_len > self.bit_len {
return Err(ReadError::NotEnoughData {
requested: bit_len,
bits_left: self.bit_len,
});
}
Ok(BitBuffer {
bytes: Rc::clone(&self.bytes),
byte_len: bit_len / 8,
bit_len,
endianness: PhantomData,
})
}
}
impl<E: Endianness> From<Vec<u8>> for BitBuffer<E> {
fn from(bytes: Vec<u8>) -> Self {
let byte_len = bytes.len();
BitBuffer {
bytes: Rc::new(bytes),
byte_len,
bit_len: byte_len * 8,
endianness: PhantomData,
}
}
}
impl<E: Endianness> Clone for BitBuffer<E> {
fn clone(&self) -> Self {
BitBuffer {
bytes: Rc::clone(&self.bytes),
byte_len: self.byte_len,
bit_len: self.bit_len,
endianness: PhantomData,
}
}
}
impl<E: Endianness> Debug for BitBuffer<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"BitBuffer {{ bit_len: {}, endianness: {} }}",
self.bit_len,
if E::is_le() {
"LittleEndian"
} else {
"BigEndian"
}
)
}
}