1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +02:00

add big endian

This commit is contained in:
Robin Appelman 2019-02-20 19:47:09 +01:00
commit c33a9a711b
3 changed files with 166 additions and 42 deletions

32
src/endianness.rs Normal file
View file

@ -0,0 +1,32 @@
/// Trait for specifying endianness of bit buffer
pub trait Endianness {
fn is_le() -> bool;
fn is_be() -> bool;
}
/// Trait for specifying that the bit buffer is big endian
pub struct BigEndian {
}
/// Trait for specifying that the bit buffer is little endian
pub struct LittleEndian {
}
macro_rules! impl_endianness {
($type:ty, $le:expr) => {
impl Endianness for $type {
#[inline]
fn is_le() -> bool {
$le
}
#[inline]
fn is_be() -> bool {
!$le
}
}
}
}
impl_endianness!(BigEndian, false);
impl_endianness!(LittleEndian, true);

View file

@ -5,15 +5,22 @@
extern crate test; extern crate test;
use endianness::Endianness;
use is_signed::IsSigned; use is_signed::IsSigned;
use num_traits::{Float, PrimInt}; use num_traits::{Float, PrimInt};
use std::cmp::min; use std::cmp::min;
use std::marker::PhantomData;
use std::mem::size_of; use std::mem::size_of;
use std::ops::BitOrAssign; use std::ops::BitOrAssign;
pub use endianness::{LittleEndian, BigEndian};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod is_signed; mod is_signed;
mod endianness;
const USIZE_SIZE: usize = size_of::<usize>();
/// Errors that can be returned when trying to read from a buffer /// Errors that can be returned when trying to read from a buffer
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
@ -38,15 +45,17 @@ pub enum ReadError {
pub type Result<T> = std::result::Result<T, ReadError>; pub type Result<T> = std::result::Result<T, ReadError>;
/// Buffer that allows reading integers of arbitrary bit length and non byte-aligned integers /// Buffer that allows reading integers of arbitrary bit length and non byte-aligned integers
pub struct BitBuffer<'a> { ///
/// The endianness used when reading from the buffer is specified as type parameter
pub struct BitBuffer<'a, E>
where E: Endianness {
bytes: &'a [u8], bytes: &'a [u8],
bit_len: usize, bit_len: usize,
byte_len: usize, byte_len: usize,
endianness: PhantomData<E>,
} }
const USIZE_SIZE: usize = size_of::<usize>(); impl<'a, E> BitBuffer<'a, E> where E: Endianness {
impl<'a> BitBuffer<'a> {
/// Create a new BitBuffer from a byte slice with included padding /// Create a new BitBuffer from a byte slice with included padding
/// ///
/// The padding is required because the optimized method for reading bits can overshoot the last requested bit /// The padding is required because the optimized method for reading bits can overshoot the last requested bit
@ -59,18 +68,18 @@ impl<'a> BitBuffer<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use bitbuffer::BitBuffer; /// use bitbuffer::{BitBuffer, LittleEndian};
/// ///
/// let bytes:&[u8] =&[ /// let bytes:&[u8] =&[
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001, /// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111, /// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
/// 0, 0, 0, 0, 0, 0, 0, 0 /// 0, 0, 0, 0, 0, 0, 0, 0
/// ]; /// ];
/// let buffer = BitBuffer::from_padded_slice(bytes, 8); /// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
/// ``` /// ```
/// ///
/// ///
pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> BitBuffer<'a> { pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> Self {
if byte_len > bytes.len() - (USIZE_SIZE - 1) { if byte_len > bytes.len() - (USIZE_SIZE - 1) {
panic!("Not enough padding on slice, at least {} bytes of padding are required", USIZE_SIZE - 1); panic!("Not enough padding on slice, at least {} bytes of padding are required", USIZE_SIZE - 1);
} }
@ -78,6 +87,7 @@ impl<'a> BitBuffer<'a> {
bytes, bytes,
byte_len, byte_len,
bit_len: byte_len * 8, bit_len: byte_len * 8,
endianness: PhantomData,
} }
} }
@ -108,8 +118,16 @@ impl<'a> BitBuffer<'a> {
let bytes: [u8; USIZE_SIZE] = unsafe { let bytes: [u8; USIZE_SIZE] = unsafe {
*(slice.as_ptr() as *const [u8; USIZE_SIZE]) *(slice.as_ptr() as *const [u8; USIZE_SIZE])
}; };
let container = usize::from_le_bytes(bytes); let container = if E::is_le() {
let shifted = container >> bit_offset; usize::from_le_bytes(bytes)
} else {
usize::from_be_bytes(bytes)
};
let shifted = if E::is_le() {
container >> bit_offset
} else {
container >> USIZE_SIZE * 8 - bit_offset - count
};
let mask = !(usize::max_value() << count); let mask = !(usize::max_value() << count);
Ok(shifted & mask) Ok(shifted & mask)
} }
@ -123,14 +141,14 @@ impl<'a> BitBuffer<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use bitbuffer::BitBuffer; /// use bitbuffer::{BitBuffer, LittleEndian};
/// ///
/// let bytes:&[u8] =&[ /// let bytes:&[u8] =&[
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001, /// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111, /// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
/// 0, 0, 0, 0, 0, 0, 0, 0 /// 0, 0, 0, 0, 0, 0, 0, 0
/// ]; /// ];
/// let buffer = BitBuffer::from_padded_slice(bytes, 8); /// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
/// let result = buffer.read_bool(6); /// let result = buffer.read_bool(6);
/// ``` /// ```
pub fn read_bool(&self, position: usize) -> Result<bool> { pub fn read_bool(&self, position: usize) -> Result<bool> {
@ -160,14 +178,14 @@ impl<'a> BitBuffer<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use bitbuffer::BitBuffer; /// use bitbuffer::{BitBuffer, LittleEndian};
/// ///
/// let bytes:&[u8] =&[ /// let bytes:&[u8] =&[
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001, /// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111, /// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
/// 0, 0, 0, 0, 0, 0, 0, 0 /// 0, 0, 0, 0, 0, 0, 0, 0
/// ]; /// ];
/// let buffer = BitBuffer::from_padded_slice(bytes, 8); /// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
/// let result = buffer.read::<u16>(10, 9); /// let result = buffer.read::<u16>(10, 9);
/// ``` /// ```
pub fn read<T>(&self, position: usize, count: usize) -> Result<T> pub fn read<T>(&self, position: usize, count: usize) -> Result<T>
@ -201,7 +219,13 @@ impl<'a> BitBuffer<'a> {
while left_to_read > 0 { while left_to_read > 0 {
let bits_left = self.bit_len - read_pos; let bits_left = self.bit_len - read_pos;
let read = min(min(left_to_read, max_read), bits_left); let read = min(min(left_to_read, max_read), bits_left);
partial |= T::from(self.read_usize(read_pos, read)?).unwrap() << bit_offset; let data = T::from(self.read_usize(read_pos, read)?).unwrap();
if E::is_le() {
partial |= data << bit_offset;
} else {
partial = partial << read;
partial |= data;
}
bit_offset += read; bit_offset += read;
read_pos += read; read_pos += read;
left_to_read -= read; left_to_read -= read;
@ -230,14 +254,14 @@ impl<'a> BitBuffer<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use bitbuffer::BitBuffer; /// use bitbuffer::{BitBuffer, LittleEndian};
/// ///
/// let bytes:&[u8] =&[ /// let bytes:&[u8] =&[
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001, /// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111, /// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
/// 0, 0, 0, 0, 0, 0, 0, 0 /// 0, 0, 0, 0, 0, 0, 0, 0
/// ]; /// ];
/// let buffer = BitBuffer::from_padded_slice(bytes, 8); /// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
/// let bytes = buffer.read_bytes(5, 3); /// let bytes = buffer.read_bytes(5, 3);
/// ``` /// ```
pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> { pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> {
@ -267,14 +291,14 @@ impl<'a> BitBuffer<'a> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use bitbuffer::BitBuffer; /// use bitbuffer::{BitBuffer, LittleEndian};
/// ///
/// let bytes:&[u8] =&[ /// let bytes:&[u8] =&[
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001, /// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111, /// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
/// 0, 0, 0, 0, 0, 0, 0, 0 /// 0, 0, 0, 0, 0, 0, 0, 0
/// ]; /// ];
/// let buffer = BitBuffer::from_padded_slice(bytes, 8); /// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
/// let result = buffer.read_float::<f32>(10); /// let result = buffer.read_float::<f32>(10);
/// ``` /// ```
pub fn read_float<T>(&self, position: usize) -> Result<T> pub fn read_float<T>(&self, position: usize) -> Result<T>

View file

@ -10,8 +10,8 @@ const BYTES: &'static [u8] = &[
]; ];
#[test] #[test]
fn read_u8() { fn read_u8_le() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u8>(0, 1).unwrap(), 0b1); assert_eq!(buffer.read::<u8>(0, 1).unwrap(), 0b1);
assert_eq!(buffer.read::<u8>(1, 1).unwrap(), 0b0); assert_eq!(buffer.read::<u8>(1, 1).unwrap(), 0b0);
@ -22,22 +22,48 @@ fn read_u8() {
} }
#[test] #[test]
fn read_u16() { fn read_u8_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u8>(0, 1).unwrap(), 0b1);
assert_eq!(buffer.read::<u8>(1, 1).unwrap(), 0b0);
assert_eq!(buffer.read::<u8>(2, 2).unwrap(), 0b11);
assert_eq!(buffer.read::<u8>(0, 3).unwrap(), 0b101);
assert_eq!(buffer.read::<u8>(7, 5).unwrap(), 0b1011_0);
assert_eq!(buffer.read::<u8>(6, 5).unwrap(), 0b01_011);
}
#[test]
fn read_u16_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u16>(6, 12).unwrap(), 0b00_0110_1010_10); assert_eq!(buffer.read::<u16>(6, 12).unwrap(), 0b00_0110_1010_10);
} }
#[test] #[test]
fn read_u32() { fn read_u16_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u16>(6, 12).unwrap(), 0b01_0110_1010_10);
}
#[test]
fn read_u32_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_1001_1010_1100_0110_1010_10);
} }
#[test] #[test]
fn read_u64() { fn read_u32_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_0110_1010_1010_1100_1001_10);
}
#[test]
fn read_u64_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<u64>(6, 34).unwrap(), 0b1001_1001_1001_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<u64>(6, 34).unwrap(), 0b1001_1001_1001_1001_1010_1100_0110_1010_10);
assert_eq!(buffer.read::<u64>(6, 60).unwrap(), 0b01_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<u64>(6, 60).unwrap(), 0b01_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10);
@ -45,32 +71,65 @@ fn read_u64() {
} }
#[test] #[test]
fn read_i8() { fn read_u64_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i8>(0, 3).unwrap(), -0b1); assert_eq!(buffer.read::<u64>(6, 34).unwrap(), 0b01_0110_1010_1010_1100_1001_1001_1001_1001);
assert_eq!(buffer.read::<u64>(6, 60).unwrap(), 0b01_0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_10);
assert_eq!(buffer.read::<u64>(6, 64).unwrap(), 0b01_0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_1001_10);
}
#[test]
fn read_i8_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i8>(0, 3).unwrap(), -0b01);
assert_eq!(buffer.read::<i8>(0, 8).unwrap(), -0b011_0101); assert_eq!(buffer.read::<i8>(0, 8).unwrap(), -0b011_0101);
} }
#[test] #[test]
fn read_i16() { fn read_i8_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i8>(1, 2).unwrap(), 0b1);
assert_eq!(buffer.read::<i8>(0, 3).unwrap(), -0b01);
assert_eq!(buffer.read::<i8>(0, 8).unwrap(), -0b011_0101);
}
#[test]
fn read_i16_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i16>(6, 12).unwrap(), 0b0_0110_1010_10); assert_eq!(buffer.read::<i16>(6, 12).unwrap(), 0b0_0110_1010_10);
assert_eq!(buffer.read::<i16>(6, 13).unwrap(), -0b00_0110_1010_10); assert_eq!(buffer.read::<i16>(6, 13).unwrap(), -0b00_0110_1010_10);
} }
#[test] #[test]
fn read_i32() { fn read_i16_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i16>(6, 12).unwrap(), 0b1_0110_1010_10);
assert_eq!(buffer.read::<i16>(7, 12).unwrap(), -0b0110_1010_101);
}
#[test]
fn read_i32_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i32>(6, 24).unwrap(), 0b1_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<i32>(6, 24).unwrap(), 0b1_1001_1010_1100_0110_1010_10);
assert_eq!(buffer.read::<i32>(6, 26).unwrap(), -0b001_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<i32>(6, 26).unwrap(), -0b001_1001_1010_1100_0110_1010_10);
} }
#[test] #[test]
fn read_i64() { fn read_i32_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i32>(7, 24).unwrap(), -0b0110_1010_1010_1100_1001_100);
}
#[test]
fn read_i64_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i64>(6, 34).unwrap(), -0b001_1001_1001_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<i64>(6, 34).unwrap(), -0b001_1001_1001_1001_1010_1100_0110_1010_10);
assert_eq!(buffer.read::<i64>(6, 59).unwrap(), -0b1110_01111001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10); assert_eq!(buffer.read::<i64>(6, 59).unwrap(), -0b1110_01111001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10);
@ -78,20 +137,29 @@ fn read_i64() {
} }
#[test] #[test]
fn read_f32() { fn read_i64_be() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read::<i64>(7, 34).unwrap(), -0b0110_1010_1010_1100_1001_1001_1001_1001_1);
assert_eq!(buffer.read::<i64>(7, 60).unwrap(), -0b0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_100);
assert_eq!(buffer.read::<i64>(7, 64).unwrap(), -0b0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_1001_100);
}
#[test]
fn read_f32_le() {
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0); assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0);
} }
#[test] #[test]
fn read_f64() { fn read_f64_le() {
let buffer = BitBuffer::from_padded_slice(BYTES, 12); let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0); assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0);
} }
fn read_perf(buffer: BitBuffer) -> u16 { fn read_perf<E: Endianness>(buffer: BitBuffer<E>) -> u16 {
let size = 5; let size = 5;
let mut pos = 0; let mut pos = 0;
let len = buffer.bit_len(); let len = buffer.bit_len();
@ -113,7 +181,7 @@ fn perf(b: &mut Bencher) {
file.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); file.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
let bytes = file.as_slice(); let bytes = file.as_slice();
b.iter(|| { b.iter(|| {
let buffer = BitBuffer::from_padded_slice(&bytes, length); let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(&bytes, length);
let data = read_perf(buffer); let data = read_perf(buffer);
assert_eq!(data, 43943); assert_eq!(data, 43943);
test::black_box(data); test::black_box(data);