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

some docs

This commit is contained in:
Robin Appelman 2019-03-05 16:01:55 +01:00
commit f54d8748ad
3 changed files with 91 additions and 44 deletions

View file

@ -5,7 +5,7 @@
//! //!
//! Once you have a BitStream, there are 2 different approaches of reading data //! Once you have a BitStream, there are 2 different approaches of reading data
//! //!
//! - read primitives, Strings and byte arrays, using [`read_bool`], [`read_int`], [`read_float`], [`read_byes`] and [`read_string`] //! - read primitives, Strings and byte arrays, using [`read_bool`], [`read_int`], [`read_float`], [`read_bytes`] and [`read_string`]
//! - read any type implementing the [`BitRead`] or [`BitReadSized`] traits using [`read`] and [`read_sized`] //! - read any type implementing the [`BitRead`] or [`BitReadSized`] traits using [`read`] and [`read_sized`]
//! - [`BitRead`] is for types that can be read without requiring any size info (e.g. null-terminal strings, floats, whole integers, etc) //! - [`BitRead`] is for types that can be read without requiring any size info (e.g. null-terminal strings, floats, whole integers, etc)
//! - [`BitReadSized`] is for types that require external sizing information to be read (fixed length strings, arbitrary length integers //! - [`BitReadSized`] is for types that require external sizing information to be read (fixed length strings, arbitrary length integers
@ -45,16 +45,14 @@
//! [`read_bool`]: struct.BitStream.html#method.read_bool //! [`read_bool`]: struct.BitStream.html#method.read_bool
//! [`read_int`]: struct.BitStream.html#method.read_int //! [`read_int`]: struct.BitStream.html#method.read_int
//! [`read_float`]: struct.BitStream.html#method.read_float //! [`read_float`]: struct.BitStream.html#method.read_float
//! [`read_byes`]: struct.BitStream.html#method.read_bytes //! [`read_bytes`]: struct.BitStream.html#method.read_bytes
//! [`read_string`]: struct.BitStream.html#method.read_string //! [`read_string`]: struct.BitStream.html#method.read_string
//! [`read`]: struct.BitStream.html#method.read
//! [`read_sized`]: struct.BitStream.html#method.read_sized
//! [`BitRead`]: trait.BitRead.html //! [`BitRead`]: trait.BitRead.html
//! [`BitReadSized`]: trait.BitReadSized.html //! [`BitReadSized`]: trait.BitReadSized.html
#![warn(missing_docs)] #![warn(missing_docs)]
//#![feature(test)]
// for bench on nightly
//extern crate test;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@ -153,4 +151,4 @@ pub fn bit_size_of<T: BitSize>() -> usize {
#[inline(always)] #[inline(always)]
pub fn bit_size_of_sized<T: BitSizeSized>(size: usize) -> usize { pub fn bit_size_of_sized<T: BitSizeSized>(size: usize) -> usize {
T::bit_size(size) T::bit_size(size)
} }

View file

@ -1,8 +1,8 @@
use crate::{BitStream, Endianness, Result}; use crate::{BitStream, Endianness, Result};
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::cell::RefCell;
/// Trait for types that can be read from a stream without requiring the size to be configured /// Trait for types that can be read from a stream without requiring the size to be configured
/// ///
@ -18,7 +18,7 @@ use std::cell::RefCell;
/// The size for a field can be set using 3 different methods /// The size for a field can be set using 3 different methods
/// - set the size as an integer using the `size` attribute, /// - set the size as an integer using the `size` attribute,
/// - use a previously defined field as the size using the `size` attribute /// - use a previously defined field as the size using the `size` attribute
/// - read a set number of bits as an integer, using the resulting value as size using the `read_bits` attribute /// - read a set number of bits as an integer, using the resulting value as size using the `size_bits` attribute
/// ///
/// ## Examples /// ## Examples
/// ///
@ -98,14 +98,14 @@ pub trait BitSize {
macro_rules! impl_read_int { macro_rules! impl_read_int {
($type:ty, $len:expr) => { ($type:ty, $len:expr) => {
impl<E: Endianness> BitRead<E> for $type { impl<E: Endianness> BitRead<E> for $type {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<$type> { fn read(stream: &mut BitStream<E>) -> Result<$type> {
stream.read_int::<$type>($len) stream.read_int::<$type>($len)
} }
} }
impl BitSize for $type { impl BitSize for $type {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
$len $len
} }
@ -125,49 +125,49 @@ impl_read_int!(i64, 64);
impl_read_int!(i128, 128); impl_read_int!(i128, 128);
impl<E: Endianness> BitRead<E> for f32 { impl<E: Endianness> BitRead<E> for f32 {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<f32> { fn read(stream: &mut BitStream<E>) -> Result<f32> {
stream.read_float::<f32>() stream.read_float::<f32>()
} }
} }
impl BitSize for f32 { impl BitSize for f32 {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
32 32
} }
} }
impl<E: Endianness> BitRead<E> for f64 { impl<E: Endianness> BitRead<E> for f64 {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<f64> { fn read(stream: &mut BitStream<E>) -> Result<f64> {
stream.read_float::<f64>() stream.read_float::<f64>()
} }
} }
impl BitSize for f64 { impl BitSize for f64 {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
64 64
} }
} }
impl<E: Endianness> BitRead<E> for bool { impl<E: Endianness> BitRead<E> for bool {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<bool> { fn read(stream: &mut BitStream<E>) -> Result<bool> {
stream.read_bool() stream.read_bool()
} }
} }
impl BitSize for bool { impl BitSize for bool {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
1 1
} }
} }
impl<E: Endianness> BitRead<E> for String { impl<E: Endianness> BitRead<E> for String {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<String> { fn read(stream: &mut BitStream<E>) -> Result<String> {
stream.read_string(None) stream.read_string(None)
} }
@ -189,7 +189,7 @@ impl<E: Endianness> BitRead<E> for String {
/// - set the size as an integer using the `size` attribute, /// - set the size as an integer using the `size` attribute,
/// - use a previously defined field as the size using the `size` attribute /// - use a previously defined field as the size using the `size` attribute
/// - based on the input size by setting `size` attribute to `"input_size"` /// - based on the input size by setting `size` attribute to `"input_size"`
/// - read a set number of bits as an integer, using the resulting value as size using the `read_bits` attribute /// - read a set number of bits as an integer, using the resulting value as size using the `size_bits` attribute
/// ///
/// ## Examples /// ## Examples
/// ///
@ -251,14 +251,14 @@ pub trait BitSizeSized {
macro_rules! impl_read_int_sized { macro_rules! impl_read_int_sized {
($type:ty) => { ($type:ty) => {
impl<E: Endianness> BitReadSized<E> for $type { impl<E: Endianness> BitReadSized<E> for $type {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>, size: usize) -> Result<$type> { fn read(stream: &mut BitStream<E>, size: usize) -> Result<$type> {
stream.read_int::<$type>(size) stream.read_int::<$type>(size)
} }
} }
impl BitSizeSized for $type { impl BitSizeSized for $type {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
size size
} }
@ -278,14 +278,14 @@ impl_read_int_sized!(i64);
impl_read_int_sized!(i128); impl_read_int_sized!(i128);
impl<E: Endianness> BitReadSized<E> for String { impl<E: Endianness> BitReadSized<E> for String {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>, size: usize) -> Result<String> { fn read(stream: &mut BitStream<E>, size: usize) -> Result<String> {
stream.read_string(Some(size)) stream.read_string(Some(size))
} }
} }
impl BitSizeSized for String { impl BitSizeSized for String {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
8 * size 8 * size
} }
@ -303,7 +303,7 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Option<T> {
} }
impl<T: BitSize> BitSize for Option<T> { impl<T: BitSize> BitSize for Option<T> {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
1 + T::bit_size() 1 + T::bit_size()
} }
@ -320,21 +320,21 @@ impl<E: Endianness, T: BitReadSized<E>> BitReadSized<E> for Option<T> {
} }
impl<T: BitSizeSized> BitSizeSized for Option<T> { impl<T: BitSizeSized> BitSizeSized for Option<T> {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
1 + T::bit_size(size) 1 + T::bit_size(size)
} }
} }
impl<E: Endianness> BitReadSized<E> for BitStream<E> { impl<E: Endianness> BitReadSized<E> for BitStream<E> {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> { fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
stream.read_bits(size) stream.read_bits(size)
} }
} }
impl<E: Endianness> BitSizeSized for BitStream<E> { impl<E: Endianness> BitSizeSized for BitStream<E> {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
size size
} }
@ -352,7 +352,7 @@ impl<E: Endianness, T: BitRead<E>> BitReadSized<E> for Vec<T> {
} }
impl<T: BitSize> BitSizeSized for Vec<T> { impl<T: BitSize> BitSizeSized for Vec<T> {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
size * T::bit_size() size * T::bit_size()
} }
@ -360,7 +360,7 @@ impl<T: BitSize> BitSizeSized for Vec<T> {
// Once we have something like https://github.com/rust-lang/rfcs/issues/1053 we can do this optimization // Once we have something like https://github.com/rust-lang/rfcs/issues/1053 we can do this optimization
//impl<E: Endianness> ReadSized<E> for Vec<u8> { //impl<E: Endianness> ReadSized<E> for Vec<u8> {
// #[inline(always)] // #[inline]
// fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> { // fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
// stream.read_bytes(size) // stream.read_bytes(size)
// } // }
@ -380,7 +380,7 @@ impl<E: Endianness, K: BitRead<E> + Eq + Hash, T: BitRead<E>> BitReadSized<E> fo
} }
impl<K: BitSize, T: BitSize> BitSizeSized for HashMap<K, T> { impl<K: BitSize, T: BitSize> BitSizeSized for HashMap<K, T> {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
size * (K::bit_size() + T::bit_size()) size * (K::bit_size() + T::bit_size())
} }
@ -394,11 +394,11 @@ impl<K: BitSize, T: BitSize> BitSizeSized for HashMap<K, T> {
/// [`BitSize`]: trait.BitSize.html /// [`BitSize`]: trait.BitSize.html
pub struct LazyBitRead<T: BitRead<E> + BitSize, E: Endianness> { pub struct LazyBitRead<T: BitRead<E> + BitSize, E: Endianness> {
source: RefCell<BitStream<E>>, source: RefCell<BitStream<E>>,
inner_type: PhantomData<T> inner_type: PhantomData<T>,
} }
impl<T: BitRead<E> + BitSize, E: Endianness> LazyBitRead<T, E> { impl<T: BitRead<E> + BitSize, E: Endianness> LazyBitRead<T, E> {
#[inline(always)] #[inline]
/// Get the contents of the lazy struct /// Get the contents of the lazy struct
pub fn read(self) -> Result<T> { pub fn read(self) -> Result<T> {
self.source.borrow_mut().read::<T>() self.source.borrow_mut().read::<T>()
@ -406,18 +406,18 @@ impl<T: BitRead<E> + BitSize, E: Endianness> LazyBitRead<T, E> {
} }
impl<T: BitRead<E> + BitSize, E: Endianness> BitRead<E> for LazyBitRead<T, E> { impl<T: BitRead<E> + BitSize, E: Endianness> BitRead<E> for LazyBitRead<T, E> {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<Self> { fn read(stream: &mut BitStream<E>) -> Result<Self> {
let bit_size = T::bit_size(); let bit_size = T::bit_size();
Ok(LazyBitRead { Ok(LazyBitRead {
source: RefCell::new(stream.read_bits(bit_size)?), source: RefCell::new(stream.read_bits(bit_size)?),
inner_type: PhantomData inner_type: PhantomData,
}) })
} }
} }
impl<T: BitRead<E> + BitSize, E: Endianness> BitSize for LazyBitRead<T, E> { impl<T: BitRead<E> + BitSize, E: Endianness> BitSize for LazyBitRead<T, E> {
#[inline(always)] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
T::bit_size() T::bit_size()
} }
@ -432,11 +432,11 @@ impl<T: BitRead<E> + BitSize, E: Endianness> BitSize for LazyBitRead<T, E> {
pub struct LazyBitReadSized<T: BitReadSized<E> + BitSizeSized, E: Endianness> { pub struct LazyBitReadSized<T: BitReadSized<E> + BitSizeSized, E: Endianness> {
source: RefCell<BitStream<E>>, source: RefCell<BitStream<E>>,
size: usize, size: usize,
inner_type: PhantomData<T> inner_type: PhantomData<T>,
} }
impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> LazyBitReadSized<T, E> { impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> LazyBitReadSized<T, E> {
#[inline(always)] #[inline]
/// Get the contents of the lazy struct /// Get the contents of the lazy struct
pub fn value(self) -> Result<T> { pub fn value(self) -> Result<T> {
self.source.borrow_mut().read_sized::<T>(self.size) self.source.borrow_mut().read_sized::<T>(self.size)
@ -444,20 +444,20 @@ impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> LazyBitReadSized<T, E> {
} }
impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> BitReadSized<E> for LazyBitReadSized<T, E> { impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> BitReadSized<E> for LazyBitReadSized<T, E> {
#[inline(always)] #[inline]
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> { fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
let bit_size = T::bit_size(size); let bit_size = T::bit_size(size);
Ok(LazyBitReadSized { Ok(LazyBitReadSized {
source: RefCell::new(stream.read_bits(bit_size)?), source: RefCell::new(stream.read_bits(bit_size)?),
inner_type: PhantomData, inner_type: PhantomData,
size size,
}) })
} }
} }
impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> BitSizeSized for LazyBitReadSized<T, E> { impl<T: BitReadSized<E> + BitSizeSized, E: Endianness> BitSizeSized for LazyBitReadSized<T, E> {
#[inline(always)] #[inline]
fn bit_size(size: usize) -> usize { fn bit_size(size: usize) -> usize {
T::bit_size(size) T::bit_size(size)
} }
} }

View file

@ -472,13 +472,45 @@ where
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
/// #[inline(always)] ///
/// ```
/// # use bitstream_reader::{BitBuffer, BitStream, LittleEndian, Result};
/// use bitstream_reader::BitRead;
/// #
/// #[derive(BitRead, Debug, PartialEq)]
/// struct ComplexType {
/// first: u8,
/// #[size = 15]
/// second: u16,
/// third: bool,
/// }
/// #
/// # fn main() -> Result<()> {
/// # let bytes = vec![
/// # 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// # 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
/// # ];
/// # let buffer = BitBuffer::new(bytes, LittleEndian);
/// # let mut stream = BitStream::new(buffer);
/// let data: ComplexType = stream.read()?;
/// assert_eq!(data, ComplexType {
/// first: 0b1011_0101,
/// second: 0b010_1100_0110_1010,
/// third: true,
/// });
/// #
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn read<T: BitRead<E>>(&mut self) -> Result<T> { pub fn read<T: BitRead<E>>(&mut self) -> Result<T> {
T::read(self) T::read(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
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@ -497,7 +529,24 @@ where
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[inline(always)] ///
/// ```
/// # use bitstream_reader::{BitBuffer, BitStream, LittleEndian, Result};
/// #
/// # fn main() -> Result<()> {
/// # let bytes = vec![
/// # 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
/// # 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
/// # ];
/// # let buffer = BitBuffer::new(bytes, LittleEndian);
/// # let mut stream = BitStream::new(buffer);
/// let data: Vec<u16> = stream.read_sized(3)?;
/// assert_eq!(data, vec![0b0110_1010_1011_0101, 0b1001_1001_1010_1100, 0b1001_1001_1001_1001]);
/// #
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn read_sized<T: BitReadSized<E>>(&mut self, size: usize) -> Result<T> { pub fn read_sized<T: BitReadSized<E>>(&mut self, size: usize) -> Result<T> {
T::read(self, size) T::read(self, size)
} }