mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
docs
This commit is contained in:
parent
4a8f0e1db6
commit
64f24a2921
1 changed files with 104 additions and 2 deletions
106
src/lib.rs
106
src/lib.rs
|
|
@ -1,9 +1,12 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
|
//! Tools for reading integers of arbitrary bit length and non byte-aligned integers and other data types
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
use is_signed::IsSigned;
|
use is_signed::IsSigned;
|
||||||
use num_traits::{PrimInt};
|
use num_traits::PrimInt;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::ops::BitOrAssign;
|
use std::ops::BitOrAssign;
|
||||||
|
|
@ -12,20 +15,29 @@ use std::ops::BitOrAssign;
|
||||||
mod tests;
|
mod tests;
|
||||||
mod is_signed;
|
mod is_signed;
|
||||||
|
|
||||||
|
/// Errors that can be returned when trying to read from a buffer
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||||
pub enum ReadError {
|
pub enum ReadError {
|
||||||
|
/// Too many bits requested to fit in the requested data type
|
||||||
TooManyBits {
|
TooManyBits {
|
||||||
|
/// The number of bits requested to read
|
||||||
requested: usize,
|
requested: usize,
|
||||||
|
/// The number of bits that fit in the requested data type
|
||||||
max: usize,
|
max: usize,
|
||||||
},
|
},
|
||||||
|
/// Not enough data in the buffer to read all requested bits
|
||||||
NotEnoughData {
|
NotEnoughData {
|
||||||
|
/// The number of bits requested to read
|
||||||
requested: usize,
|
requested: usize,
|
||||||
|
/// the number of bits left in the buffer
|
||||||
bits_left: usize,
|
bits_left: usize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Either the read bits in the requested format or a [`ReadError`](enum.ReadError.html)
|
||||||
pub type Result<T> = std::result::Result<T, ReadError>;
|
pub type Result<T> = std::result::Result<T, ReadError>;
|
||||||
|
|
||||||
|
/// Buffer that allows reading integers of arbitrary bit length and non byte-aligned integers
|
||||||
pub struct BitBuffer<'a> {
|
pub struct BitBuffer<'a> {
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
bit_len: usize,
|
bit_len: usize,
|
||||||
|
|
@ -52,7 +64,33 @@ macro_rules! array_ref {
|
||||||
const USIZE_SIZE: usize = size_of::<usize>();
|
const USIZE_SIZE: usize = size_of::<usize>();
|
||||||
|
|
||||||
impl<'a> BitBuffer<'a> {
|
impl<'a> BitBuffer<'a> {
|
||||||
|
/// Create a new BitBuffer from a byte slice with included padding
|
||||||
|
///
|
||||||
|
/// The padding is required because the optimized method for reading bits can overshoot the last requested bit
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// When not enough padding is provided (3 bytes on 32bit systems, 7 bytes on 64 bit systems)
|
||||||
|
/// this method will panic
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use bitbuffer::BitBuffer;
|
||||||
|
///
|
||||||
|
/// let bytes:&[u8] =&[
|
||||||
|
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||||
|
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||||
|
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
/// ];
|
||||||
|
/// let buffer = BitBuffer::from_padded_slice(bytes, 8);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
///
|
||||||
pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> BitBuffer<'a> {
|
pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> BitBuffer<'a> {
|
||||||
|
if byte_len > bytes.len() - (USIZE_SIZE - 1) {
|
||||||
|
panic!("Not enough padding on slice, at least {} bytes of padding are required", USIZE_SIZE - 1);
|
||||||
|
}
|
||||||
BitBuffer {
|
BitBuffer {
|
||||||
bytes,
|
bytes,
|
||||||
byte_len,
|
byte_len,
|
||||||
|
|
@ -60,10 +98,16 @@ impl<'a> BitBuffer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The available number of bits in the buffer
|
||||||
|
///
|
||||||
|
/// Note that this does not included any padding from the source slice
|
||||||
pub fn bit_len(&self) -> usize {
|
pub fn bit_len(&self) -> usize {
|
||||||
self.bit_len
|
self.bit_len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The available number of bytes in the buffer
|
||||||
|
///
|
||||||
|
/// Note that this does not included any padding from the source slice
|
||||||
pub fn byte_len(&self) -> usize {
|
pub fn byte_len(&self) -> usize {
|
||||||
self.byte_len
|
self.byte_len
|
||||||
}
|
}
|
||||||
|
|
@ -87,6 +131,25 @@ impl<'a> BitBuffer<'a> {
|
||||||
Ok(shifted & mask)
|
Ok(shifted & mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a single bit from the buffer as boolean
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use bitbuffer::BitBuffer;
|
||||||
|
///
|
||||||
|
/// let bytes:&[u8] =&[
|
||||||
|
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||||
|
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||||
|
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
/// ];
|
||||||
|
/// let buffer = BitBuffer::from_padded_slice(bytes, 8);
|
||||||
|
/// let result = buffer.read_bool(6);
|
||||||
|
/// ```
|
||||||
pub fn read_bool(&self, position: usize) -> Result<bool> {
|
pub fn read_bool(&self, position: usize) -> Result<bool> {
|
||||||
let byte_index = position / 8;
|
let byte_index = position / 8;
|
||||||
let bit_offset = position & 7;
|
let bit_offset = position & 7;
|
||||||
|
|
@ -104,6 +167,26 @@ impl<'a> BitBuffer<'a> {
|
||||||
Ok(shifted & mask == 1)
|
Ok(shifted & mask == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a sequence of bits from the buffer 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 bitbuffer::BitBuffer;
|
||||||
|
///
|
||||||
|
/// let bytes:&[u8] =&[
|
||||||
|
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||||
|
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||||
|
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
/// ];
|
||||||
|
/// let buffer = BitBuffer::from_padded_slice(bytes, 8);
|
||||||
|
/// let result = buffer.read::<u16>(10, 9);
|
||||||
|
/// ```
|
||||||
pub fn read<T>(&self, position: usize, count: usize) -> Result<T>
|
pub fn read<T>(&self, position: usize, count: usize) -> Result<T>
|
||||||
where T: PrimInt + BitOrAssign + IsSigned
|
where T: PrimInt + BitOrAssign + IsSigned
|
||||||
{
|
{
|
||||||
|
|
@ -122,7 +205,7 @@ impl<'a> BitBuffer<'a> {
|
||||||
let raw = self.read_usize(position, count)?;
|
let raw = self.read_usize(position, count)?;
|
||||||
let max_signed_value = (1 << (type_bit_size - 1)) - 1;
|
let max_signed_value = (1 << (type_bit_size - 1)) - 1;
|
||||||
if T::is_signed() && raw > max_signed_value {
|
if T::is_signed() && raw > max_signed_value {
|
||||||
return Ok(T::zero() - T::from(raw & max_signed_value).unwrap())
|
return Ok(T::zero() - T::from(raw & max_signed_value).unwrap());
|
||||||
} else {
|
} else {
|
||||||
T::from(raw).unwrap()
|
T::from(raw).unwrap()
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +238,25 @@ impl<'a> BitBuffer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a series of bytes from the buffer
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - [`ReadError::NotEnoughData`](enum.ReadError.html#variant.NotEnoughData): not enough bits available in the buffer
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use bitbuffer::BitBuffer;
|
||||||
|
///
|
||||||
|
/// let bytes:&[u8] =&[
|
||||||
|
/// 0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
|
||||||
|
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
|
||||||
|
/// 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
/// ];
|
||||||
|
/// let buffer = BitBuffer::from_padded_slice(bytes, 8);
|
||||||
|
/// let bytes = buffer.read_bytes(5, 3);
|
||||||
|
/// ```
|
||||||
pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> {
|
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);
|
data.reserve_exact(byte_count);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue