mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
remove padded optimization for the sake of api cleanness
This commit is contained in:
parent
c39b8675ac
commit
eee2cf5c43
3 changed files with 36 additions and 102 deletions
|
|
@ -48,37 +48,21 @@ impl IsPadded for Padded {
|
|||
/// ];
|
||||
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
|
||||
/// ```
|
||||
///
|
||||
/// You can also provide a slice padded with at least `size_of::<usize>() - 1` bytes,
|
||||
/// when the input slice is padded, the BitBuffer can use some optimizations which result in a ~1.5 time performance increase
|
||||
///
|
||||
/// ```
|
||||
/// use bitstream_reader::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes: &[u8] = &[
|
||||
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||
/// ];
|
||||
/// let buffer = BitBuffer::from_padded(bytes.to_vec(), 8, LittleEndian);
|
||||
/// ```
|
||||
pub struct BitBuffer<E, S>
|
||||
pub struct BitBuffer<E>
|
||||
where
|
||||
E: Endianness,
|
||||
S: IsPadded,
|
||||
{
|
||||
bytes: Vec<u8>,
|
||||
bit_len: usize,
|
||||
byte_len: usize,
|
||||
endianness: PhantomData<E>,
|
||||
is_padded: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<E> BitBuffer<E, NonPadded>
|
||||
impl<E> BitBuffer<E>
|
||||
where
|
||||
E: Endianness,
|
||||
{
|
||||
/// Create a new BitBuffer from a byte slice
|
||||
/// Create a new BitBuffer from a byte vector
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -98,57 +82,13 @@ where
|
|||
byte_len,
|
||||
bit_len: byte_len * 8,
|
||||
endianness: PhantomData,
|
||||
is_padded: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> BitBuffer<E, Padded>
|
||||
impl<E> BitBuffer<E>
|
||||
where
|
||||
E: Endianness,
|
||||
{
|
||||
/// Create a new BitBuffer from a byte slice with included padding
|
||||
///
|
||||
/// by including at least `size_of::<usize>() - 1` bytes of padding reading can be further optimized
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if not enough bytes of padding are included
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bitstream_reader::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes: &[u8] = &[
|
||||
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||
/// ];
|
||||
/// let buffer = BitBuffer::from_padded(bytes.to_vec(), 8, LittleEndian);
|
||||
/// ```
|
||||
pub fn from_padded(bytes: Vec<u8>, byte_len: usize, _endianness: E) -> Self {
|
||||
if bytes.len() < byte_len + USIZE_SIZE - 1 {
|
||||
panic!(
|
||||
"not enough padding bytes, {} required, {} provided",
|
||||
USIZE_SIZE - 1,
|
||||
byte_len - bytes.len()
|
||||
)
|
||||
}
|
||||
BitBuffer {
|
||||
bytes,
|
||||
byte_len,
|
||||
bit_len: byte_len * 8,
|
||||
endianness: PhantomData,
|
||||
is_padded: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, S> BitBuffer<E, S>
|
||||
where
|
||||
E: Endianness,
|
||||
S: IsPadded,
|
||||
{
|
||||
/// The available number of bits in the buffer
|
||||
pub fn bit_len(&self) -> usize {
|
||||
|
|
@ -167,11 +107,7 @@ where
|
|||
bits_left: self.bit_len - position,
|
||||
});
|
||||
}
|
||||
let byte_index = if S::is_padded() {
|
||||
position / 8
|
||||
} else {
|
||||
min(position / 8, self.byte_len - USIZE_SIZE)
|
||||
};
|
||||
let byte_index = min(position / 8, self.byte_len - USIZE_SIZE);
|
||||
let bit_offset = position - byte_index * 8;
|
||||
let raw_container: &usize = unsafe {
|
||||
// this is safe here because it's already verified that there is enough data in the slice
|
||||
|
|
|
|||
50
src/read.rs
50
src/read.rs
|
|
@ -1,16 +1,16 @@
|
|||
use crate::{BitStream, Endianness, IsPadded, Result};
|
||||
use crate::{BitStream, Endianness, Result};
|
||||
|
||||
/// Trait for types that can be read from a stream without requiring the size to be configured
|
||||
pub trait Read<E: Endianness, P: IsPadded>: Sized {
|
||||
pub trait Read<E: Endianness>: Sized {
|
||||
/// Read the type from stream
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<Self>;
|
||||
fn read(stream: &mut BitStream<E>) -> Result<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_read_int {
|
||||
($type:ty, $len:expr) => {
|
||||
impl<E: Endianness, P: IsPadded> Read<E, P> for $type {
|
||||
impl<E: Endianness> Read<E> for $type {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<$type> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<$type> {
|
||||
stream.read_int::<$type>($len)
|
||||
}
|
||||
}
|
||||
|
|
@ -28,45 +28,45 @@ impl_read_int!(i32, 32);
|
|||
impl_read_int!(i64, 64);
|
||||
impl_read_int!(i128, 128);
|
||||
|
||||
impl<E: Endianness, P: IsPadded> Read<E, P> for f32 {
|
||||
impl<E: Endianness> Read<E> for f32 {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<f32> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<f32> {
|
||||
stream.read_float::<f32>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Endianness, P: IsPadded> Read<E, P> for f64 {
|
||||
impl<E: Endianness> Read<E> for f64 {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<f64> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<f64> {
|
||||
stream.read_float::<f64>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Endianness, P: IsPadded> Read<E, P> for bool {
|
||||
impl<E: Endianness> Read<E> for bool {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<bool> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<bool> {
|
||||
stream.read_bool()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Endianness, P: IsPadded> Read<E, P> for String {
|
||||
impl<E: Endianness> Read<E> for String {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<String> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<String> {
|
||||
stream.read_string(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that can be read from a stream wit requiring the size to be configured
|
||||
pub trait ReadSized<E: Endianness, P: IsPadded>: Sized {
|
||||
pub trait ReadSized<E: Endianness>: Sized {
|
||||
/// Read the type from stream
|
||||
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self>;
|
||||
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_read_int_sized {
|
||||
($type:ty) => {
|
||||
impl<E: Endianness, P: IsPadded> ReadSized<E, P> for $type {
|
||||
impl<E: Endianness> ReadSized<E> for $type {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<$type> {
|
||||
fn read(stream: &mut BitStream<E>, size: usize) -> Result<$type> {
|
||||
stream.read_int::<$type>(size)
|
||||
}
|
||||
}
|
||||
|
|
@ -84,16 +84,16 @@ impl_read_int_sized!(i32);
|
|||
impl_read_int_sized!(i64);
|
||||
impl_read_int_sized!(i128);
|
||||
|
||||
impl<E: Endianness, P: IsPadded> ReadSized<E, P> for String {
|
||||
impl<E: Endianness> ReadSized<E> for String {
|
||||
#[inline(always)]
|
||||
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<String> {
|
||||
fn read(stream: &mut BitStream<E>, size: usize) -> Result<String> {
|
||||
stream.read_string(Some(size))
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a boolean, if true, read the value, else return None
|
||||
impl<E: Endianness, P: IsPadded, T: Read<E, P>> Read<E, P> for Option<T> {
|
||||
fn read(stream: &mut BitStream<E, P>) -> Result<Self> {
|
||||
impl<E: Endianness, T: Read<E>> Read<E> for Option<T> {
|
||||
fn read(stream: &mut BitStream<E>) -> Result<Self> {
|
||||
if stream.read()? {
|
||||
Ok(Some(stream.read()?))
|
||||
} else {
|
||||
|
|
@ -102,8 +102,8 @@ impl<E: Endianness, P: IsPadded, T: Read<E, P>> Read<E, P> for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Endianness, P: IsPadded, T: Read<E, P>> ReadSized<E, P> for Vec<T> {
|
||||
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self> {
|
||||
impl<E: Endianness, T: Read<E>> ReadSized<E> for Vec<T> {
|
||||
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
|
||||
let mut vec = Vec::with_capacity(size);
|
||||
for _ in 0..size {
|
||||
vec.push(stream.read()?)
|
||||
|
|
@ -113,9 +113,9 @@ impl<E: Endianness, P: IsPadded, T: Read<E, P>> ReadSized<E, P> for Vec<T> {
|
|||
}
|
||||
|
||||
// Once we have something like https://github.com/rust-lang/rfcs/issues/1053 we can do this optimization
|
||||
//impl<E: Endianness, P: IsPadded> ReadSized<E, P> for Vec<u8> {
|
||||
//impl<E: Endianness> ReadSized<E> for Vec<u8> {
|
||||
// #[inline(always)]
|
||||
// fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self> {
|
||||
// fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
|
||||
// stream.read_bytes(size)
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -24,21 +24,19 @@ use crate::{Read, ReadError, ReadSized, Result};
|
|||
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
|
||||
/// let mut stream = BitStream::new(buffer, None, None);
|
||||
/// ```
|
||||
pub struct BitStream<E, S>
|
||||
pub struct BitStream<E>
|
||||
where
|
||||
E: Endianness,
|
||||
S: IsPadded,
|
||||
{
|
||||
buffer: Rc<BitBuffer<E, S>>,
|
||||
buffer: Rc<BitBuffer<E>>,
|
||||
start_pos: usize,
|
||||
pos: usize,
|
||||
bit_len: usize,
|
||||
}
|
||||
|
||||
impl<E, S> BitStream<E, S>
|
||||
impl<E> BitStream<E>
|
||||
where
|
||||
E: Endianness,
|
||||
S: IsPadded,
|
||||
{
|
||||
/// Create a new stream for a buffer
|
||||
///
|
||||
|
|
@ -59,7 +57,7 @@ where
|
|||
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
|
||||
/// let mut stream = BitStream::new(buffer, None, None);
|
||||
/// ```
|
||||
pub fn new(buffer: BitBuffer<E, S>, start_pos: Option<usize>, bit_len: Option<usize>) -> Self {
|
||||
pub fn new(buffer: BitBuffer<E>, start_pos: Option<usize>, bit_len: Option<usize>) -> Self {
|
||||
let buffer_len = buffer.bit_len();
|
||||
let start = start_pos.unwrap_or_default();
|
||||
if start > buffer_len {
|
||||
|
|
@ -413,12 +411,12 @@ where
|
|||
}
|
||||
|
||||
/// Read a value based on the provided type
|
||||
pub fn read<T: Read<E, S>>(&mut self) -> Result<T> {
|
||||
pub fn read<T: Read<E>>(&mut self) -> Result<T> {
|
||||
T::read(self)
|
||||
}
|
||||
|
||||
/// Read a value based on the provided type and size
|
||||
pub fn read_sized<T: ReadSized<E, S>>(&mut self, size: usize) -> Result<T> {
|
||||
pub fn read_sized<T: ReadSized<E>>(&mut self, size: usize) -> Result<T> {
|
||||
T::read(self, size)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue