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

add bitstream

This commit is contained in:
Robin Appelman 2019-02-22 23:42:13 +01:00
commit 7cd64b9ad7

View file

@ -5,8 +5,8 @@
// for bench on nightly // for bench on nightly
//extern crate test; //extern crate test;
use endianness::Endianness;
pub use endianness::{BigEndian, LittleEndian}; pub use endianness::{BigEndian, LittleEndian};
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;
@ -38,6 +38,13 @@ pub enum ReadError {
/// the number of bits left in the buffer /// the number of bits left in the buffer
bits_left: usize, bits_left: usize,
}, },
/// The requested position is outside the bounds of the buffer
IndexOutOfBounds {
/// The requested position
pos: usize,
/// the number of bits in the buffer
size: usize,
},
} }
/// Mark source slice as not including padding /// Mark source slice as not including padding
@ -97,7 +104,7 @@ pub type Result<T> = std::result::Result<T, ReadError>;
/// let buffer = BitBuffer::from_padded_slice(bytes, 8, LittleEndian); /// let buffer = BitBuffer::from_padded_slice(bytes, 8, LittleEndian);
/// ``` /// ```
pub struct BitBuffer<'a, E, S> pub struct BitBuffer<'a, E, S>
where where
E: Endianness, E: Endianness,
S: IsPadded, S: IsPadded,
{ {
@ -109,7 +116,7 @@ where
} }
impl<'a, E> BitBuffer<'a, E, NonPadded> impl<'a, E> BitBuffer<'a, E, NonPadded>
where where
E: Endianness, E: Endianness,
{ {
/// Create a new BitBuffer from a byte slice /// Create a new BitBuffer from a byte slice
@ -138,7 +145,7 @@ where
} }
impl<'a, E> BitBuffer<'a, E, Padded> impl<'a, E> BitBuffer<'a, E, Padded>
where where
E: Endianness, E: Endianness,
{ {
/// Create a new BitBuffer from a byte slice with included padding /// Create a new BitBuffer from a byte slice with included padding
@ -180,7 +187,7 @@ where
} }
impl<'a, E, S> BitBuffer<'a, E, S> impl<'a, E, S> BitBuffer<'a, E, S>
where where
E: Endianness, E: Endianness,
S: IsPadded, S: IsPadded,
{ {
@ -406,3 +413,348 @@ where
} }
} }
} }
/// Stream that provides an easy way to iterate trough a BitBuffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// ```
pub struct BitStream<'a, E, S>
where
E: Endianness,
S: IsPadded,
{
buffer: &'a BitBuffer<'a, E, S>,
start_pos: usize,
pos: usize,
bit_len: usize,
}
impl<'a, E, S> BitStream<'a, E, S>
where
E: Endianness,
S: IsPadded, {
/// Create a new stream for a buffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// ```
pub fn new(buffer: &'a BitBuffer<'a, E, S>, start_pos: Option<usize>, bit_len: Option<usize>) -> Self {
BitStream {
start_pos: start_pos.unwrap_or(0),
pos: start_pos.unwrap_or(0),
bit_len: bit_len.unwrap_or(buffer.bit_len()),
buffer,
}
}
fn verify_bits_left(&self, count: usize) -> Result<()> {
if self.bits_left() < count {
Err(ReadError::NotEnoughData {
bits_left: self.bits_left(),
requested: count,
})
} else {
Ok(())
}
}
/// Read a single bit from the stream as boolean
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// assert_eq!(stream.read_bool().unwrap(), true);
/// assert_eq!(stream.read_bool().unwrap(), false);
/// assert_eq!(stream.pos(), 2);
/// ```
pub fn read_bool(&mut self) -> Result<bool> {
self.verify_bits_left(1)?;
let result = self.buffer.read_bool(self.pos);
match result {
Ok(_) => self.pos += 1,
Err(_) => {}
}
result
}
/// Read a sequence of bits from the stream as integer
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
/// - [`ReadError::TooManyBits`](enum.ReadError.html#variant.TooManyBits): to many bits requested for the chosen integer type
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// assert_eq!(stream.read::<u16>(3).unwrap(), 0b101);
/// assert_eq!(stream.read::<u16>(3).unwrap(), 0b110);
/// assert_eq!(stream.pos(), 6);
/// ```
pub fn read<T>(&mut self, count: usize) -> Result<T>
where
T: PrimInt + BitOrAssign + IsSigned, {
self.verify_bits_left(count)?;
let result = self.buffer.read(self.pos, count);
match result {
Ok(_) => self.pos += count,
Err(_) => {}
}
result
}
/// Read a sequence of bits from the stream as float
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// let result = stream.read_float::<f32>().unwrap();
/// assert_eq!(stream.pos(), 32);
/// ```
pub fn read_float<T>(&mut self) -> Result<T>
where
T: Float, {
let count = size_of::<T>() * 8;
self.verify_bits_left(count)?;
let result = self.buffer.read_float(self.pos);
match result {
Ok(_) => self.pos += count,
Err(_) => {}
}
result
}
/// Read a series of bytes from the stream
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// let bytes = stream.read_bytes(3).unwrap();
/// assert_eq!(bytes, &[0b1011_0101, 0b0110_1010, 0b1010_1100]);
/// assert_eq!(stream.pos(), 24);
/// ```
pub fn read_bytes(&mut self, byte_count: usize) -> Result<Vec<u8>> {
let count = byte_count * 8;
self.verify_bits_left(count)?;
let result = self.buffer.read_bytes(self.pos, byte_count);
match result {
Ok(_) => self.pos += count,
Err(_) => {}
}
result
}
/// Read a sequence of bits from the stream as a BitStream
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// let mut bits = stream.read_bits(3).unwrap();
/// assert_eq!(stream.pos(), 3);
/// assert_eq!(bits.pos(), 0);
/// assert_eq!(bits.bit_len(), 3);
/// assert_eq!(stream.read::<u8>(3).unwrap(), 0b110);
/// assert_eq!(bits.read::<u8>(3).unwrap(), 0b101);
/// ```
pub fn read_bits(&mut self, count: usize) -> Result<Self> {
self.verify_bits_left(count)?;
let result = BitStream::new(&self.buffer, Some(self.pos), Some(count));
self.pos += count;
Ok(result)
}
/// Skip a number of bits in the stream
///
/// # Errors
///
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer to skip
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// stream.skip(3).unwrap();
/// assert_eq!(stream.pos(), 3);
/// assert_eq!(stream.read::<u8>(3).unwrap(), 0b110);
/// ```
pub fn skip(&mut self, count: usize) -> Result<()> {
self.verify_bits_left(count)?;
self.pos += count;
Ok(())
}
/// Set the position of the stream
///
/// # Errors
///
/// - [`ReadError::IndexOutOfBounds`](enum.ReadError.html#variant.IndexOutOfBounds): new position is outside the bounds of the stream
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// stream.set_pos(3).unwrap();
/// assert_eq!(stream.pos(), 3);
/// assert_eq!(stream.read::<u8>(3).unwrap(), 0b110);
/// ```
pub fn set_pos(&mut self, pos: usize) -> Result<()> {
if pos > self.bit_len {
return Err(ReadError::IndexOutOfBounds {
pos,
size: self.bit_len,
});
}
self.pos = pos + self.start_pos;
Ok(())
}
/// Get the length of the stream in bits
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// assert_eq!(stream.bit_len(), 64);
/// ```
pub fn bit_len(&self) -> usize {
self.bit_len
}
/// Get the current position in the stream
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// assert_eq!(stream.pos(), 0);
/// stream.skip(5).unwrap();
/// assert_eq!(stream.pos(), 5);
/// ```
pub fn pos(&self) -> usize {
self.pos - self.start_pos
}
/// Get the number of bits left in the stream
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, BitStream, LittleEndian};
///
/// let bytes: &[u8] = &[
/// 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, None, None);
/// assert_eq!(stream.bits_left(), 64);
/// stream.skip(5).unwrap();
/// assert_eq!(stream.bits_left(), 59);
/// ```
pub fn bits_left(&self) -> usize {
self.bit_len - self.pos()
}
}