mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 00:54:07 +02:00
add unchecked reading to BitRead and BitReadSized
This commit is contained in:
parent
28b1d15bff
commit
55eb866eb6
3 changed files with 160 additions and 3 deletions
83
src/read.rs
83
src/read.rs
|
|
@ -92,6 +92,11 @@ pub trait BitRead<E: Endianness>: Sized {
|
||||||
/// Read the type from stream
|
/// Read the type from stream
|
||||||
fn read(stream: &mut BitStream<E>) -> Result<Self>;
|
fn read(stream: &mut BitStream<E>) -> Result<Self>;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
|
||||||
|
Self::read(stream)
|
||||||
|
}
|
||||||
|
|
||||||
/// The number of bits that will be read or None if the number of bits will change depending
|
/// The number of bits that will be read or None if the number of bits will change depending
|
||||||
/// on the bit stream
|
/// on the bit stream
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -121,6 +126,11 @@ macro_rules! impl_read_int {
|
||||||
stream.read_int::<$type>(size_of::<$type>() * 8)
|
stream.read_int::<$type>(size_of::<$type>() * 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<$type> {
|
||||||
|
Ok(stream.read_int_unchecked::<$type>(size_of::<$type>() * 8))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(size_of::<$type>() * 8)
|
Some(size_of::<$type>() * 8)
|
||||||
|
|
@ -137,6 +147,13 @@ macro_rules! impl_read_int_nonzero {
|
||||||
Ok(<$type>::new(stream.read()?))
|
Ok(<$type>::new(stream.read()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<LittleEndian>) -> Result<Self> {
|
||||||
|
Ok(<$type>::new(
|
||||||
|
stream.read_int_unchecked(size_of::<$type>() * 8),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(size_of::<$type>() * 8)
|
Some(size_of::<$type>() * 8)
|
||||||
|
|
@ -149,6 +166,13 @@ macro_rules! impl_read_int_nonzero {
|
||||||
Ok(<$type>::new(stream.read()?))
|
Ok(<$type>::new(stream.read()?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<BigEndian>) -> Result<Self> {
|
||||||
|
Ok(<$type>::new(
|
||||||
|
stream.read_int_unchecked(size_of::<$type>() * 8),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(size_of::<$type>() * 8)
|
Some(size_of::<$type>() * 8)
|
||||||
|
|
@ -180,6 +204,11 @@ impl<E: Endianness> BitRead<E> for f32 {
|
||||||
stream.read_float::<f32>()
|
stream.read_float::<f32>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<f32> {
|
||||||
|
Ok(stream.read_float_unchecked::<f32>())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(32)
|
Some(32)
|
||||||
|
|
@ -192,6 +221,11 @@ impl<E: Endianness> BitRead<E> for f64 {
|
||||||
stream.read_float::<f64>()
|
stream.read_float::<f64>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<f64> {
|
||||||
|
Ok(stream.read_float_unchecked::<f64>())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(64)
|
Some(64)
|
||||||
|
|
@ -204,6 +238,11 @@ impl<E: Endianness> BitRead<E> for bool {
|
||||||
stream.read_bool()
|
stream.read_bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<bool> {
|
||||||
|
Ok(stream.read_bool_unchecked())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
Some(1)
|
Some(1)
|
||||||
|
|
@ -223,6 +262,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Rc<T> {
|
||||||
Ok(Rc::new(T::read(stream)?))
|
Ok(Rc::new(T::read(stream)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
|
||||||
|
Ok(Rc::new(T::read_unchecked(stream)?))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
T::bit_size()
|
T::bit_size()
|
||||||
|
|
@ -235,6 +279,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Arc<T> {
|
||||||
Ok(Arc::new(T::read(stream)?))
|
Ok(Arc::new(T::read(stream)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
|
||||||
|
Ok(Arc::new(T::read_unchecked(stream)?))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
T::bit_size()
|
T::bit_size()
|
||||||
|
|
@ -247,6 +296,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Box<T> {
|
||||||
Ok(Box::new(T::read(stream)?))
|
Ok(Box::new(T::read(stream)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
|
||||||
|
Ok(Box::new(T::read_unchecked(stream)?))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size() -> Option<usize> {
|
fn bit_size() -> Option<usize> {
|
||||||
T::bit_size().and_then(|sum| T::bit_size().map(|size| sum + size))
|
T::bit_size().and_then(|sum| T::bit_size().map(|size| sum + size))
|
||||||
|
|
@ -341,6 +395,11 @@ pub trait BitReadSized<E: Endianness>: Sized {
|
||||||
/// Read the type from stream
|
/// Read the type from stream
|
||||||
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>;
|
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
|
||||||
|
Self::read(stream, size)
|
||||||
|
}
|
||||||
|
|
||||||
/// The number of bits that will be read or None if the number of bits will change depending
|
/// The number of bits that will be read or None if the number of bits will change depending
|
||||||
/// on the bit stream
|
/// on the bit stream
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -357,6 +416,10 @@ macro_rules! impl_read_int_sized {
|
||||||
stream.read_int::<$type>(size)
|
stream.read_int::<$type>(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<$type> {
|
||||||
|
Ok(stream.read_int_unchecked::<$type>(size))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size_sized(size: usize) -> Option<usize> {
|
fn bit_size_sized(size: usize) -> Option<usize> {
|
||||||
Some(size)
|
Some(size)
|
||||||
|
|
@ -431,6 +494,15 @@ impl<E: Endianness, T: BitRead<E>> BitReadSized<E> for Vec<T> {
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
|
||||||
|
let mut vec = Vec::with_capacity(size);
|
||||||
|
for _ in 0..size {
|
||||||
|
vec.push(stream.read_unchecked()?)
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size_sized(size: usize) -> Option<usize> {
|
fn bit_size_sized(size: usize) -> Option<usize> {
|
||||||
T::bit_size().map(|element_size| size * element_size)
|
T::bit_size().map(|element_size| size * element_size)
|
||||||
|
|
@ -457,6 +529,17 @@ impl<E: Endianness, K: BitRead<E> + Eq + Hash, T: BitRead<E>> BitReadSized<E> fo
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
|
||||||
|
let mut map = HashMap::with_capacity(size);
|
||||||
|
for _ in 0..size {
|
||||||
|
let key = stream.read_unchecked()?;
|
||||||
|
let value = stream.read_unchecked()?;
|
||||||
|
map.insert(key, value);
|
||||||
|
}
|
||||||
|
Ok(map)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn bit_size_sized(size: usize) -> Option<usize> {
|
fn bit_size_sized(size: usize) -> Option<usize> {
|
||||||
if let (Some(key_size), Some(value_size)) = (K::bit_size(), T::bit_size()) {
|
if let (Some(key_size), Some(value_size)) = (K::bit_size(), T::bit_size()) {
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,14 @@ where
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read_bool_unchecked(&mut self) -> bool {
|
||||||
|
let result = self.buffer.read_bool_unchecked(self.pos);
|
||||||
|
self.pos += 1;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// Read a sequence of bits from the stream as integer
|
/// Read a sequence of bits from the stream as integer
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
|
@ -195,9 +203,9 @@ where
|
||||||
T: Float + UncheckedPrimitiveFloat,
|
T: Float + UncheckedPrimitiveFloat,
|
||||||
{
|
{
|
||||||
let count = size_of::<T>() * 8;
|
let count = size_of::<T>() * 8;
|
||||||
|
let result = self.buffer.read_float_unchecked(self.pos);
|
||||||
self.pos += count;
|
self.pos += count;
|
||||||
|
result
|
||||||
self.buffer.read_float_unchecked(self.pos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a series of bytes from the stream
|
/// Read a series of bytes from the stream
|
||||||
|
|
@ -240,8 +248,9 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Vec<u8> {
|
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Vec<u8> {
|
||||||
let count = byte_count * 8;
|
let count = byte_count * 8;
|
||||||
|
let result = self.buffer.read_bytes_unchecked(self.pos, byte_count);
|
||||||
self.pos += count;
|
self.pos += count;
|
||||||
self.buffer.read_bytes_unchecked(self.pos, byte_count)
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a series of bytes from the stream as utf8 string
|
/// Read a series of bytes from the stream as utf8 string
|
||||||
|
|
@ -547,6 +556,12 @@ where
|
||||||
T::read(self)
|
T::read(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read_unchecked<T: BitRead<E>>(&mut self) -> Result<T> {
|
||||||
|
T::read_unchecked(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Read a value based on the provided type and size
|
/// Read a value based on the provided type and size
|
||||||
///
|
///
|
||||||
/// The meaning of the size parameter differs depending on the type that is being read
|
/// The meaning of the size parameter differs depending on the type that is being read
|
||||||
|
|
@ -591,6 +606,12 @@ where
|
||||||
T::read(self, size)
|
T::read(self, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read_sized_unchecked<T: BitReadSized<E>>(&mut self, size: usize) -> Result<T> {
|
||||||
|
T::read_unchecked(self, size)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if we can read a number of bits from the stream
|
/// Check if we can read a number of bits from the stream
|
||||||
pub fn check_read(&self, count: usize) -> Result<()> {
|
pub fn check_read(&self, count: usize) -> Result<()> {
|
||||||
if self.bits_left() < count {
|
if self.bits_left() < count {
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,27 @@ fn read_trait() {
|
||||||
assert_eq!(Some(0b011_0101_0), f);
|
assert_eq!(Some(0b011_0101_0), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_trait_unchecked() {
|
||||||
|
unsafe {
|
||||||
|
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
|
||||||
|
let mut stream = BitStream::new(buffer);
|
||||||
|
let a: u8 = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(0b1011_0101, a);
|
||||||
|
let b: i8 = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(0b110_1010, b);
|
||||||
|
let c: i16 = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(-0b101_0011_0110_0111, c);
|
||||||
|
let d: bool = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(true, d);
|
||||||
|
let e: Option<u8> = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(None, e);
|
||||||
|
stream.set_pos(0).unwrap();
|
||||||
|
let f: Option<u8> = stream.read_unchecked().unwrap();
|
||||||
|
assert_eq!(Some(0b011_0101_0), f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn read_sized_trait() {
|
fn read_sized_trait() {
|
||||||
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
|
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
|
||||||
|
|
@ -320,6 +341,38 @@ fn read_sized_trait() {
|
||||||
assert_eq!(0b10u8, result.read_int(2).unwrap());
|
assert_eq!(0b10u8, result.read_int(2).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_sized_trait_unchecked() {
|
||||||
|
unsafe {
|
||||||
|
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
|
||||||
|
let mut stream = BitStream::new(buffer);
|
||||||
|
let a: u8 = stream.read_sized_unchecked(4).unwrap();
|
||||||
|
assert_eq!(0b1011, a);
|
||||||
|
stream.set_pos(0).unwrap();
|
||||||
|
let vec: Vec<u16> = stream.read_sized_unchecked(3).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
0b1011_0101_0110_1010,
|
||||||
|
0b1010_1100_1001_1001,
|
||||||
|
0b1001_1001_1001_1001
|
||||||
|
],
|
||||||
|
vec
|
||||||
|
);
|
||||||
|
stream.set_pos(0).unwrap();
|
||||||
|
let vec: Vec<u8> = stream.read_sized_unchecked(3).unwrap();
|
||||||
|
assert_eq!(vec![0b1011_0101, 0b0110_1010, 0b1010_1100], vec);
|
||||||
|
stream.set_pos(0).unwrap();
|
||||||
|
let result: HashMap<u8, u8> = stream.read_sized_unchecked(2).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
hashmap!(0b1011_0101 => 0b0110_1010, 0b1010_1100 => 0b1001_1001),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
stream.set_pos(0).unwrap();
|
||||||
|
let mut result: BitStream<BigEndian> = stream.read_sized_unchecked(4).unwrap();
|
||||||
|
assert_eq!(0b10u8, result.read_int(2).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(BitRead, PartialEq, Debug)]
|
#[derive(BitRead, PartialEq, Debug)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
foo: u8,
|
foo: u8,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue