1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +02:00
This commit is contained in:
Robin Appelman 2019-02-22 14:40:11 +01:00
commit b0d290311c
4 changed files with 129 additions and 63 deletions

View file

@ -5,12 +5,10 @@ pub trait Endianness {
}
/// Trait for specifying that the bit buffer is big endian
pub struct BigEndian {
}
pub struct BigEndian {}
/// Trait for specifying that the bit buffer is little endian
pub struct LittleEndian {
}
pub struct LittleEndian {}
macro_rules! impl_endianness {
($type:ty, $le:expr) => {
@ -25,7 +23,7 @@ macro_rules! impl_endianness {
!$le
}
}
}
};
}
impl_endianness!(BigEndian, false);

View file

@ -10,7 +10,7 @@ macro_rules! impl_is_signed {
$signed
}
}
}
};
}
impl_is_signed!(u8, false);

View file

@ -5,8 +5,8 @@
extern crate test;
pub use endianness::{BigEndian, LittleEndian};
use endianness::Endianness;
pub use endianness::{BigEndian, LittleEndian};
use is_signed::IsSigned;
use num_traits::{Float, PrimInt};
use std::cmp::min;
@ -14,10 +14,10 @@ use std::marker::PhantomData;
use std::mem::size_of;
use std::ops::BitOrAssign;
mod endianness;
mod is_signed;
#[cfg(test)]
mod tests;
mod is_signed;
mod endianness;
const USIZE_SIZE: usize = size_of::<usize>();
@ -47,14 +47,19 @@ pub type Result<T> = std::result::Result<T, ReadError>;
///
/// The endianness used when reading from the buffer is specified as type parameter
pub struct BitBuffer<'a, E>
where E: Endianness {
where
E: Endianness,
{
bytes: &'a [u8],
bit_len: usize,
byte_len: usize,
endianness: PhantomData<E>,
}
impl<'a, E> BitBuffer<'a, E> where E: Endianness {
impl<'a, E> BitBuffer<'a, E>
where
E: Endianness,
{
/// Create a new BitBuffer from a byte slice
///
/// # Examples
@ -98,9 +103,7 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
let byte_index = min(position / 8, self.byte_len - USIZE_SIZE);
let bit_offset = position - byte_index * 8;
let slice = &self.bytes[byte_index..byte_index + USIZE_SIZE];
let bytes: [u8; USIZE_SIZE] = unsafe {
*(slice.as_ptr() as *const [u8; USIZE_SIZE])
};
let bytes: [u8; USIZE_SIZE] = unsafe { *(slice.as_ptr() as *const [u8; USIZE_SIZE]) };
let container = if E::is_le() {
usize::from_le_bytes(bytes)
} else {
@ -171,7 +174,8 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
/// assert_eq!(result, 0b100_0110_10);
/// ```
pub fn read<T>(&self, position: usize, count: usize) -> Result<T>
where T: PrimInt + BitOrAssign + IsSigned
where
T: PrimInt + BitOrAssign + IsSigned,
{
let value = {
let type_bit_size = size_of::<T>() * 8;
@ -248,7 +252,7 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
/// assert_eq!(bytes, &[0b0_1010_101, 0b0_1100_011, 0b1_1001_101]);
/// ```
pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> {
let mut data = vec!();
let mut data = vec![];
data.reserve_exact(byte_count);
let mut byte_left = byte_count;
let max_read = size_of::<usize>() - 1;
@ -284,7 +288,8 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
/// let result = buffer.read_float::<f32>(10).unwrap();
/// ```
pub fn read_float<T>(&self, position: usize) -> Result<T>
where T: Float
where
T: Float,
{
if size_of::<T>() == 4 {
let int = self.read::<u32>(position, 32)?;

View file

@ -1,11 +1,20 @@
use std::fs;
use super::*;
use std::fs;
use test::Bencher;
const BYTES: &'static [u8] = &[
0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
0b1011_0101,
0b0110_1010,
0b1010_1100,
0b1001_1001,
0b1001_1001,
0b1001_1001,
0b1001_1001,
0b1110_0111,
0b1001_1001,
0b1001_1001,
0b1001_1001,
0b1110_0111,
];
#[test]
@ -50,33 +59,60 @@ fn read_u16_be() {
fn read_u32_le() {
let buffer: BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
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]
fn read_u32_be() {
let buffer: BitBuffer<BigEndian> = BitBuffer::new(BYTES);
assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_0110_1010_1010_1100_1001_10);
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::new(BYTES);
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, 64).unwrap(), 0b01_1001_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10);
assert_eq!(buffer.read::<u64>(8, 62).unwrap(), 0b01_1001_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010);
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, 64).unwrap(),
0b01_1001_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10
);
assert_eq!(
buffer.read::<u64>(8, 62).unwrap(),
0b01_1001_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010
);
}
#[test]
fn read_u64_be() {
let buffer: BitBuffer<BigEndian> = BitBuffer::new(BYTES);
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);
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]
@ -116,33 +152,60 @@ fn read_i16_be() {
fn read_i32_le() {
let buffer: BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
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, 24).unwrap(),
0b1_1001_1010_1100_0110_1010_10
);
assert_eq!(
buffer.read::<i32>(6, 26).unwrap(),
-0b001_1001_1010_1100_0110_1010_10
);
}
#[test]
fn read_i32_be() {
let buffer: BitBuffer<BigEndian> = BitBuffer::new(BYTES);
assert_eq!(buffer.read::<i32>(7, 24).unwrap(), -0b0110_1010_1010_1100_1001_100);
assert_eq!(
buffer.read::<i32>(7, 24).unwrap(),
-0b0110_1010_1010_1100_1001_100
);
}
#[test]
fn read_i64_le() {
let buffer: BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
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>(1, 64).unwrap(), -0b1110_01111001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_1011_010);
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>(1, 64).unwrap(),
-0b1110_01111001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_1011_010
);
}
#[test]
fn read_i64_be() {
let buffer: BitBuffer<BigEndian> = BitBuffer::new(BYTES);
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);
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]