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

add traits that allow for reading arbitrary types from stream

This commit is contained in:
Robin Appelman 2019-02-27 12:41:43 +01:00
commit ad56d05dbe
4 changed files with 127 additions and 1 deletions

View file

@ -8,12 +8,14 @@
pub use buffer::{BitBuffer, IsPadded, NonPadded, Padded}; pub use buffer::{BitBuffer, IsPadded, NonPadded, Padded};
pub use endianness::*; pub use endianness::*;
pub use read::{Read, ReadSize};
pub use std::string::FromUtf8Error; pub use std::string::FromUtf8Error;
pub use stream::BitStream; pub use stream::BitStream;
mod buffer; mod buffer;
mod endianness; mod endianness;
mod is_signed; mod is_signed;
mod read;
mod stream; mod stream;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

92
src/read.rs Normal file
View file

@ -0,0 +1,92 @@
use crate::{BitStream, Endianness, IsPadded, Result};
/// Trait for types that can be read from a stream without requiring the size to be configured
pub trait Read<'a, E: Endianness, P: IsPadded>: Sized {
/// Read the type from stream
fn read(stream: &mut BitStream<'a, E, P>) -> Result<Self>;
}
macro_rules! impl_read_int {
($type:ty, $len:expr) => {
impl<'a, E: Endianness, P: IsPadded> Read<'a, E, P> for $type {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>) -> Result<$type> {
stream.read_int::<$type>($len)
}
}
};
}
impl_read_int!(u8, 8);
impl_read_int!(u16, 16);
impl_read_int!(u32, 32);
impl_read_int!(u64, 64);
impl_read_int!(u128, 128);
impl_read_int!(i8, 8);
impl_read_int!(i16, 16);
impl_read_int!(i32, 32);
impl_read_int!(i64, 64);
impl_read_int!(i128, 128);
impl<'a, E: Endianness, P: IsPadded> Read<'a, E, P> for f32 {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>) -> Result<f32> {
stream.read_float::<f32>()
}
}
impl<'a, E: Endianness, P: IsPadded> Read<'a, E, P> for f64 {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>) -> Result<f64> {
stream.read_float::<f64>()
}
}
impl<'a, E: Endianness, P: IsPadded> Read<'a, E, P> for bool {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>) -> Result<bool> {
stream.read_bool()
}
}
impl<'a, E: Endianness, P: IsPadded> Read<'a, E, P> for String {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>) -> 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 ReadSize<'a, E: Endianness, P: IsPadded>: Sized {
/// Read the type from stream
fn read(stream: &mut BitStream<'a, E, P>, size: usize) -> Result<Self>;
}
macro_rules! impl_read_int_sized {
($type:ty) => {
impl<'a, E: Endianness, P: IsPadded> ReadSize<'a, E, P> for $type {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>, size: usize) -> Result<$type> {
stream.read_int::<$type>(size)
}
}
};
}
impl_read_int_sized!(u8);
impl_read_int_sized!(u16);
impl_read_int_sized!(u32);
impl_read_int_sized!(u64);
impl_read_int_sized!(u128);
impl_read_int_sized!(i8);
impl_read_int_sized!(i16);
impl_read_int_sized!(i32);
impl_read_int_sized!(i64);
impl_read_int_sized!(i128);
impl<'a, E: Endianness, P: IsPadded> ReadSize<'a, E, P> for String {
#[inline(always)]
fn read(stream: &mut BitStream<'a, E, P>, size: usize) -> Result<String> {
stream.read_string(Some(size))
}
}

View file

@ -7,7 +7,7 @@ use crate::buffer::IsPadded;
use crate::endianness::Endianness; use crate::endianness::Endianness;
use crate::is_signed::IsSigned; use crate::is_signed::IsSigned;
use crate::BitBuffer; use crate::BitBuffer;
use crate::{ReadError, Result}; use crate::{Read, ReadError, ReadSize, Result};
/// Stream that provides an easy way to iterate trough a BitBuffer /// Stream that provides an easy way to iterate trough a BitBuffer
/// ///
@ -409,4 +409,14 @@ where
pub fn bits_left(&self) -> usize { pub fn bits_left(&self) -> usize {
self.bit_len - self.pos() self.bit_len - self.pos()
} }
/// Read a value based on the provided type
pub fn read<T: Read<'a, E, S>>(&mut self) -> Result<T> {
T::read(self)
}
/// Read a value based on the provided type and size
pub fn read_size<T: ReadSize<'a, E, S>>(&mut self, size: usize) -> Result<T> {
T::read(self, size)
}
} }

View file

@ -224,6 +224,28 @@ fn read_f64_le() {
assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0); assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0);
} }
#[test]
fn read_trait() {
let buffer = BitBuffer::new(BYTES, BigEndian);
let mut stream = BitStream::new(buffer, None, None);
let a: u8 = stream.read().unwrap();
assert_eq!(0b1011_0101, a);
let b: i8 = stream.read().unwrap();
assert_eq!(0b110_1010, b);
let c: i16 = stream.read().unwrap();
assert_eq!(-0b0010_1100_1001_1001, c);
let d: bool = stream.read().unwrap();
assert_eq!(true, d);
}
#[test]
fn read_sized_trait() {
let buffer = BitBuffer::new(BYTES, BigEndian);
let mut stream = BitStream::new(buffer, None, None);
let a: u8 = stream.read_size(4).unwrap();
assert_eq!(0b1011, a);
}
// for bench on nightly // for bench on nightly
//fn read_perf<P: IsPadded>(buffer: BitBuffer<LittleEndian, P>) -> u16 { //fn read_perf<P: IsPadded>(buffer: BitBuffer<LittleEndian, P>) -> u16 {
// let size = 5; // let size = 5;