#![warn(missing_docs)]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#[cfg(feature = "std")]
mod writer;
#[cfg(feature = "std")]
pub use writer::*;
pub trait BitReader {
fn read_bit(&mut self) -> Option<bool>;
fn read_u8(&mut self) -> Option<u8>;
fn read_i8(&mut self) -> Option<i8>;
fn read_u16(&mut self) -> Option<u16>;
fn read_i16(&mut self) -> Option<i16>;
fn read_u32(&mut self) -> Option<u32>;
fn read_i32(&mut self) -> Option<i32>;
fn read_f32(&mut self) -> Option<f32>;
fn read_u64(&mut self) -> Option<u64>;
fn read_i64(&mut self) -> Option<i64>;
fn read_f64(&mut self) -> Option<f64>;
fn read_bits(&mut self, bits: u32) -> Option<u64>;
fn read_signed_bits(&mut self, bits: u32) -> Option<i64>;
fn bytes_remaining(&self) -> usize;
fn unbuffered_bytes_remaining(&self) -> usize;
fn bits_remaining(&self) -> Option<usize>;
fn has_bits_remaining(&self, bits: usize) -> bool;
fn read_bytes(&mut self, buf: &mut [u8]) -> bool;
fn is_empty(&self) -> bool;
fn peek(&self, count: u32) -> u64;
fn consume(&mut self, count: u32);
fn refill_lookahead(&mut self);
fn lookahead_bits(&self) -> u32;
unsafe fn refill_lookahead_unchecked(&mut self);
fn byte_aligned(&self) -> bool;
}
const BYTE_WIDTH: usize = core::mem::size_of::<u64>();
const BIT_WIDTH: usize = BYTE_WIDTH * 8;
pub const MAX_READ_BITS: u32 = 56;
#[derive(Debug, Clone, Copy)]
struct BitterState<'a, const LE: bool> {
data: &'a [u8],
bit_buf: u64,
bit_count: u32,
}
impl<'a, const LE: bool> BitterState<'a, LE> {
#[inline]
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
bit_buf: 0,
bit_count: 0,
}
}
#[inline]
fn which(input: u64) -> u64 {
if LE {
input.to_le()
} else {
input.to_be()
}
}
#[inline]
fn read(&self) -> u64 {
debug_assert!(self.unbuffered_bytes() >= 8);
let mut result = [0u8; 8];
result.copy_from_slice(&self.data[..8]);
Self::which(u64::from_ne_bytes(result))
}
#[inline]
fn read_eof(&self) -> u64 {
debug_assert!(self.unbuffered_bytes() < 8);
let mut result = [0u8; 8];
let len = self.unbuffered_bytes();
result[..len].copy_from_slice(self.data);
let result = u64::from_ne_bytes(result);
Self::which(result)
}
#[inline]
fn peek_(&self, count: u32) -> u64 {
if LE {
self.bit_buf & ((1 << count) - 1)
} else if count != 0 {
self.bit_buf >> (BIT_WIDTH - count as usize)
} else {
0
}
}
#[inline]
fn consume_(&mut self, count: u32) {
if LE {
self.bit_buf >>= count;
} else {
self.bit_buf <<= count;
}
self.bit_count -= count;
}
#[inline]
fn refill_shift(&mut self, raw: u64) -> usize {
self.bit_buf |= if LE {
raw << self.bit_count
} else {
raw >> self.bit_count
};
7 - ((self.bit_count as usize >> 3) & 7)
}
#[inline]
fn refill(&mut self) {
let raw = self.read();
let shift = self.refill_shift(raw);
self.data = &self.data[shift..];
self.bit_count |= MAX_READ_BITS;
}
#[inline]
fn refill_eof(&mut self) {
let raw = self.read_eof();
let shift = self.refill_shift(raw);
let consumed = self.unbuffered_bytes().min(shift);
self.data = &self.data[consumed..];
self.bit_count += (consumed * 8) as u32;
}
#[inline]
fn has_data_for_unaligned_loads(&self) -> bool {
self.data.len() >= core::mem::size_of::<u64>()
}
#[inline]
fn unbuffered_bytes(&self) -> usize {
self.data.len()
}
#[inline]
fn bytes_remaining(&self) -> usize {
self.unbuffered_bytes() + (self.bit_count >> 3) as usize
}
#[inline]
fn bits_remaining(&self) -> Option<usize> {
self.unbuffered_bytes()
.checked_mul(8)
.map(|x| x + self.bit_count as usize)
}
#[inline]
fn has_bits_remaining(&self, bits: usize) -> bool {
let bytes = self.unbuffered_bytes();
bytes >= bits || (bytes * 8 + (self.bit_count) as usize) >= bits
}
fn remainder(&self) -> Remainder<'a> {
let unaligned_bits = self.bit_count % 8;
let lookahead_bytes = (self.bit_count / 8) as usize;
let current_ptr = self.data.as_ptr();
let total_remaining = lookahead_bytes + self.data.len();
let start_ptr = unsafe { current_ptr.sub(lookahead_bytes) };
let remaining_slice = unsafe { core::slice::from_raw_parts(start_ptr, total_remaining) };
if unaligned_bits == 0 {
Remainder::new(0, 0, remaining_slice)
} else {
let partial_byte = if LE {
(self.bit_buf & ((1 << unaligned_bits) - 1)) as u8
} else {
(self.bit_buf >> (BIT_WIDTH - unaligned_bits as usize)) as u8
};
Remainder::new(partial_byte, unaligned_bits as u8, remaining_slice)
}
}
}
macro_rules! gen_read {
($name:ident, $t:ty) => {
#[inline]
fn $name(&mut self) -> Option<$t> {
let bits = (core::mem::size_of::<$t>() * 8);
self.read_bits(bits as u32).map(|x| x as $t)
}
};
}
impl<const LE: bool> BitReader for BitterState<'_, LE> {
gen_read!(read_u8, u8);
gen_read!(read_i8, i8);
gen_read!(read_u16, u16);
gen_read!(read_i16, i16);
gen_read!(read_u32, u32);
gen_read!(read_i32, i32);
gen_read!(read_i64, i64);
#[inline]
fn read_u64(&mut self) -> Option<u64> {
self.read_bits(64)
}
fn read_bit(&mut self) -> Option<bool> {
self.read_bits(1).map(|x| x == 1)
}
#[inline]
fn read_f32(&mut self) -> Option<f32> {
self.read_u32().map(f32::from_bits)
}
#[inline]
fn read_f64(&mut self) -> Option<f64> {
self.read_u64().map(f64::from_bits)
}
#[inline]
fn read_bits(&mut self, bits: u32) -> Option<u64> {
debug_assert!(
bits <= BIT_WIDTH as u32,
"read request exceeded limit of {} bits, received {}",
BIT_WIDTH,
bits
);
if self.has_data_for_unaligned_loads() {
if bits > self.bit_count {
self.refill();
}
if bits <= MAX_READ_BITS {
let result = self.peek(bits);
self.consume(bits);
Some(result)
} else {
let lo = self.peek(MAX_READ_BITS);
self.consume(MAX_READ_BITS);
self.refill_lookahead();
let hi_len = bits - MAX_READ_BITS;
let hi = self.peek(hi_len);
self.consume(hi_len);
if LE {
Some((hi << MAX_READ_BITS) + lo)
} else {
Some((lo << hi_len) + hi)
}
}
} else if self.has_bits_remaining(bits as usize) {
self.refill_eof();
if bits <= MAX_READ_BITS {
let result = self.peek(bits);
self.consume(bits);
Some(result)
} else {
let lo = self.peek(MAX_READ_BITS);
self.consume(MAX_READ_BITS);
self.refill_eof();
let hi_len = bits - MAX_READ_BITS;
let hi = self.peek(hi_len);
self.consume(hi_len);
if LE {
Some((hi << MAX_READ_BITS) + lo)
} else {
Some((lo << hi_len) + hi)
}
}
} else {
None
}
}
#[inline]
fn read_signed_bits(&mut self, bits: u32) -> Option<i64> {
self.read_bits(bits).map(|x| sign_extend(x, bits))
}
#[inline]
fn bytes_remaining(&self) -> usize {
self.bytes_remaining()
}
#[inline]
fn unbuffered_bytes_remaining(&self) -> usize {
self.unbuffered_bytes()
}
#[inline]
fn bits_remaining(&self) -> Option<usize> {
self.bits_remaining()
}
#[inline]
fn has_bits_remaining(&self, bits: usize) -> bool {
self.has_bits_remaining(bits)
}
#[inline]
fn read_bytes(&mut self, buf: &mut [u8]) -> bool {
let lookahead_bytes = (self.bit_count >> 3) as usize;
let lookahead_consumption = lookahead_bytes.min(buf.len());
let (buf_lookahead, buf) = buf.split_at_mut(lookahead_consumption);
let (head, tail) = if buf.len() <= self.data.len() {
self.data.split_at(buf.len())
} else {
return false;
};
for dst in buf_lookahead.iter_mut() {
*dst = self.peek(8) as u8;
self.consume(8);
}
if self.byte_aligned() {
if buf.is_empty() {
return true;
}
buf.copy_from_slice(head);
self.data = tail;
self.bit_buf = 0;
self.refill_lookahead();
} else if let Some((first, buf)) = buf.split_first_mut() {
let lookahead_remainder = self.bit_count;
let lookahead_tail = self.peek(lookahead_remainder) as u8;
self.consume(lookahead_remainder);
*first = if LE {
(head[0] << lookahead_remainder) + lookahead_tail
} else {
(head[0] >> lookahead_remainder) + (lookahead_tail << (8 - lookahead_remainder))
};
let chunk_size = 16;
let buf_chunks = buf.len() / chunk_size;
let chunk_bytes = buf_chunks * chunk_size;
let (buf_body, buf) = buf.split_at_mut(chunk_bytes);
if LE {
read_n_bytes(lookahead_remainder, head, buf_body);
} else {
read_n_bytes_be(lookahead_remainder, head, buf_body);
}
self.data = unsafe { self.data.get_unchecked(chunk_bytes..) };
self.bit_buf = 0;
self.refill_lookahead();
self.consume(8 - lookahead_remainder);
self.refill_lookahead();
for dst in buf.iter_mut() {
if self.lookahead_bits() < 8 {
self.refill_lookahead();
debug_assert!(self.lookahead_bits() >= 8);
}
*dst = self.peek(8) as u8;
self.consume(8);
}
}
true
}
#[inline]
fn peek(&self, count: u32) -> u64 {
debug_assert!(
count <= self.bit_count,
"not enough bits in lookahead buffer to fulfill peek ({} vs {})",
count,
self.bit_count
);
self.peek_(count)
}
#[inline]
fn consume(&mut self, count: u32) {
debug_assert!(
count <= self.bit_count,
"not enough bits in lookahead buffer to fulfill consume ({} vs {})",
count,
self.bit_count
);
self.consume_(count);
}
#[inline]
fn lookahead_bits(&self) -> u32 {
self.bit_count
}
#[inline]
fn refill_lookahead(&mut self) {
if self.has_data_for_unaligned_loads() {
self.refill();
} else {
self.refill_eof();
}
}
#[inline]
unsafe fn refill_lookahead_unchecked(&mut self) {
debug_assert!(self.unbuffered_bytes() >= 8);
let result = unsafe { self.data.as_ptr().cast::<u64>().read_unaligned() };
let shift = self.refill_shift(Self::which(result));
self.data = unsafe { self.data.get_unchecked(shift..) };
self.bit_count |= MAX_READ_BITS;
}
#[inline]
fn is_empty(&self) -> bool {
!self.has_bits_remaining(1)
}
#[inline]
fn byte_aligned(&self) -> bool {
self.bit_count % 8 == 0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Remainder<'a> {
partial_byte: u8,
partial_bits: u8,
remaining_bytes: &'a [u8],
}
impl<'a> Remainder<'a> {
#[inline]
fn new(partial_byte: u8, partial_bits: u8, remaining_bytes: &'a [u8]) -> Self {
Self {
partial_byte,
partial_bits,
remaining_bytes,
}
}
#[inline]
pub fn partial_byte(&self) -> u8 {
self.partial_byte
}
#[inline]
pub fn partial_bits(&self) -> u8 {
self.partial_bits
}
#[inline]
pub fn data(&self) -> &'a [u8] {
self.remaining_bytes
}
}
#[derive(Debug, Clone, Copy)]
pub struct LittleEndianReader<'a>(BitterState<'a, true>);
impl<'a> LittleEndianReader<'a> {
#[inline]
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self(BitterState::new(data))
}
#[inline]
pub fn remainder(&self) -> Remainder<'a> {
self.0.remainder()
}
}
impl BitReader for LittleEndianReader<'_> {
#[inline]
fn read_bit(&mut self) -> Option<bool> {
self.0.read_bit()
}
#[inline]
fn read_u8(&mut self) -> Option<u8> {
self.0.read_u8()
}
#[inline]
fn read_i8(&mut self) -> Option<i8> {
self.0.read_i8()
}
#[inline]
fn read_u16(&mut self) -> Option<u16> {
self.0.read_u16()
}
#[inline]
fn read_i16(&mut self) -> Option<i16> {
self.0.read_i16()
}
#[inline]
fn read_u32(&mut self) -> Option<u32> {
self.0.read_u32()
}
#[inline]
fn read_i32(&mut self) -> Option<i32> {
self.0.read_i32()
}
#[inline]
fn read_f32(&mut self) -> Option<f32> {
self.0.read_f32()
}
#[inline]
fn read_u64(&mut self) -> Option<u64> {
self.0.read_u64()
}
#[inline]
fn read_i64(&mut self) -> Option<i64> {
self.0.read_i64()
}
#[inline]
fn read_f64(&mut self) -> Option<f64> {
self.0.read_f64()
}
#[inline]
fn read_bits(&mut self, bits: u32) -> Option<u64> {
self.0.read_bits(bits)
}
#[inline]
fn read_signed_bits(&mut self, bits: u32) -> Option<i64> {
self.0.read_signed_bits(bits)
}
#[inline]
fn bytes_remaining(&self) -> usize {
self.0.bytes_remaining()
}
#[inline]
fn unbuffered_bytes_remaining(&self) -> usize {
self.0.unbuffered_bytes()
}
#[inline]
fn bits_remaining(&self) -> Option<usize> {
self.0.bits_remaining()
}
#[inline]
fn has_bits_remaining(&self, bits: usize) -> bool {
self.0.has_bits_remaining(bits)
}
#[inline]
fn read_bytes(&mut self, buf: &mut [u8]) -> bool {
self.0.read_bytes(buf)
}
#[inline]
fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
fn peek(&self, count: u32) -> u64 {
self.0.peek(count)
}
#[inline]
fn consume(&mut self, count: u32) {
self.0.consume(count);
}
#[inline]
fn lookahead_bits(&self) -> u32 {
self.0.lookahead_bits()
}
#[inline]
fn refill_lookahead(&mut self) {
self.0.refill_lookahead();
}
#[inline]
unsafe fn refill_lookahead_unchecked(&mut self) {
unsafe { self.0.refill_lookahead_unchecked() };
}
#[inline]
fn byte_aligned(&self) -> bool {
self.0.byte_aligned()
}
}
#[derive(Debug, Clone, Copy)]
pub struct BigEndianReader<'a>(BitterState<'a, false>);
impl<'a> BigEndianReader<'a> {
#[inline]
#[must_use]
pub fn new(data: &'a [u8]) -> Self {
Self(BitterState::new(data))
}
#[inline]
pub fn remainder(&self) -> Remainder<'a> {
self.0.remainder()
}
}
impl BitReader for BigEndianReader<'_> {
#[inline]
fn read_bit(&mut self) -> Option<bool> {
self.0.read_bit()
}
#[inline]
fn read_u8(&mut self) -> Option<u8> {
self.0.read_u8()
}
#[inline]
fn read_i8(&mut self) -> Option<i8> {
self.0.read_i8()
}
#[inline]
fn read_u16(&mut self) -> Option<u16> {
self.0.read_u16()
}
#[inline]
fn read_i16(&mut self) -> Option<i16> {
self.0.read_i16()
}
#[inline]
fn read_u32(&mut self) -> Option<u32> {
self.0.read_u32()
}
#[inline]
fn read_i32(&mut self) -> Option<i32> {
self.0.read_i32()
}
#[inline]
fn read_f32(&mut self) -> Option<f32> {
self.0.read_f32()
}
#[inline]
fn read_u64(&mut self) -> Option<u64> {
self.0.read_u64()
}
#[inline]
fn read_i64(&mut self) -> Option<i64> {
self.0.read_i64()
}
#[inline]
fn read_f64(&mut self) -> Option<f64> {
self.0.read_f64()
}
#[inline]
fn read_bits(&mut self, bits: u32) -> Option<u64> {
self.0.read_bits(bits)
}
#[inline]
fn read_signed_bits(&mut self, bits: u32) -> Option<i64> {
self.0.read_signed_bits(bits)
}
#[inline]
fn bytes_remaining(&self) -> usize {
self.0.bytes_remaining()
}
#[inline]
fn unbuffered_bytes_remaining(&self) -> usize {
self.0.unbuffered_bytes()
}
#[inline]
fn bits_remaining(&self) -> Option<usize> {
self.0.bits_remaining()
}
#[inline]
fn has_bits_remaining(&self, bits: usize) -> bool {
self.0.has_bits_remaining(bits)
}
#[inline]
fn read_bytes(&mut self, buf: &mut [u8]) -> bool {
self.0.read_bytes(buf)
}
#[inline]
fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
fn peek(&self, count: u32) -> u64 {
self.0.peek(count)
}
#[inline]
fn consume(&mut self, count: u32) {
self.0.consume(count);
}
#[inline]
fn lookahead_bits(&self) -> u32 {
self.0.lookahead_bits()
}
#[inline]
fn refill_lookahead(&mut self) {
self.0.refill_lookahead();
}
#[inline]
unsafe fn refill_lookahead_unchecked(&mut self) {
unsafe { self.0.refill_lookahead_unchecked() };
}
#[inline]
fn byte_aligned(&self) -> bool {
self.0.byte_aligned()
}
}
#[cfg(target_endian = "little")]
pub type NativeEndianReader<'a> = LittleEndianReader<'a>;
#[cfg(target_endian = "big")]
pub type NativeEndianReader<'a> = BigEndianReader<'a>;
#[inline]
#[must_use]
pub fn sign_extend(val: u64, bits: u32) -> i64 {
debug_assert!(val.leading_zeros() as usize >= (BIT_WIDTH - bits as usize));
let m = 1i64.wrapping_shl(bits.wrapping_sub(1));
#[allow(clippy::cast_possible_wrap)]
let val = val as i64;
(val ^ m) - m
}
#[inline]
fn read_n_bytes(rem: u32, input: &[u8], out: &mut [u8]) {
let mask = (1 << rem) - 1;
let shift = 8 - rem;
for (i, o) in input.windows(2).zip(out.iter_mut()) {
let left_part = (i[0] >> shift) & mask;
let right_part = i[1] << rem;
*o = left_part + right_part;
}
}
#[inline]
fn read_n_bytes_be(rem: u32, input: &[u8], out: &mut [u8]) {
let mask = (1 << rem) - 1;
for (i, o) in input.windows(2).zip(out.iter_mut()) {
let left_part = (i[0] & mask) << (8 - rem);
let right_part = i[1] >> rem;
*o = left_part | right_part;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_u64_reads_le() {
let mut bits = LittleEndianReader::new(&[
0xff, 0xfe, 0xfa, 0xf7, 0xf5, 0xf0, 0xb1, 0xb2, 0x01, 0xff, 0xfe, 0xfa, 0xf7, 0xf5,
0xf0, 0xb1, 0xb3,
]);
let mut out = [0u8; 8];
assert!(bits.read_bytes(&mut out));
assert_eq!(u64::from_le_bytes(out), 0xb2b1_f0f5_f7fa_feff);
assert_eq!(bits.read_bits(8), Some(0x01));
assert!(bits.read_bytes(&mut out));
assert_eq!(u64::from_le_bytes(out), 0xb3b1_f0f5_f7fa_feff);
}
#[test]
fn test_has_remaining_bits() {
let mut bits = LittleEndianReader::new(&[0xff, 0xff]);
assert!(bits.has_bits_remaining(7));
assert!(bits.has_bits_remaining(8));
assert!(bits.has_bits_remaining(9));
assert!(bits.read_bits(9).is_some());
assert!(bits.has_bits_remaining(7));
assert!(!bits.has_bits_remaining(8));
assert!(!bits.has_bits_remaining(9));
assert!(bits.read_bits(7).is_some());
assert!(!bits.has_bits_remaining(7));
assert!(bits.has_bits_remaining(0));
}
#[test]
fn test_zero_bit_reads() {
let mut bits = LittleEndianReader::new(&[0xff]);
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.read_bits(0), Some(0));
assert_eq!(bits.read_u8(), Some(0xff));
assert_eq!(bits.read_bits(0), Some(0));
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.read_bits(0), Some(0));
}
#[test]
fn test_whole_bytes() {
let mut bits = LittleEndianReader::new(&[
0xff, 0xdd, 0xee, 0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd, 0xff, 0xdd, 0xee, 0xff,
0xdd,
]);
assert_eq!(bits.read_u8(), Some(0xff));
assert_eq!(bits.read_u16(), Some(u16::from_le_bytes([0xdd, 0xee])));
let mut out = [0u8; 8];
assert!(bits.read_bytes(&mut out));
assert_eq!(
u64::from_le_bytes(out),
u64::from_le_bytes([0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd, 0xff])
);
assert_eq!(
bits.read_u32(),
Some(u32::from_le_bytes([0xdd, 0xee, 0xff, 0xdd]))
);
}
#[test]
fn test_whole_bytes_shift() {
let mut bits = LittleEndianReader::new(&[
0xdf, 0xed, 0xfe, 0xdf, 0xed, 0xae, 0xba, 0xcb, 0xdc, 0xfd, 0xdf, 0xed, 0xfe, 0xdf,
0x0d,
]);
assert_eq!(bits.read_bits(4), Some(0x0f));
assert_eq!(bits.read_u16(), Some(u16::from_le_bytes([0xdd, 0xee])));
let mut out = [0u8; 8];
assert!(bits.read_bytes(&mut out));
assert_eq!(
u64::from_le_bytes(out),
u64::from_le_bytes([0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd, 0xff])
);
assert_eq!(
bits.read_u32(),
Some(u32::from_le_bytes([0xdd, 0xee, 0xff, 0xdd]))
);
}
#[test]
fn test_whole_bytes_large() {
let mut data = vec![0u8; 76];
data[0] = 0b0000_0101;
data[6] = 0b0000_1000;
data[7] = 0b0000_0010;
data[8] = 0b0000_0011;
data[28] = 0b0000_0000;
data[29] = 0b1111_1111;
data[74] = 0b1000_0000;
data[75] = 0b1011_1111;
let mut bitter = LittleEndianReader::new(&data);
assert_eq!(bitter.read_bit(), Some(true));
let mut buf = [0u8; 75];
assert!(bitter.read_bytes(&mut buf));
assert_eq!(buf[0], 0b0000_0010);
assert_eq!(buf[6], 0b0000_0100);
assert_eq!(buf[7], 0b1000_0001);
assert_eq!(buf[8], 0b0000_0001);
assert_eq!(buf[28], 0b1000_0000);
assert_eq!(buf[74], 0b1100_0000);
assert_eq!(bitter.read_bits(7), Some(0b0101_1111));
assert_eq!(bitter.read_bit(), None);
}
#[test]
fn test_has_remaining_bits2() {
let mut bits = LittleEndianReader::new(&[0xff, 0xff, 0xff, 0xff]);
assert!(bits.read_bits(31).is_some());
assert!(!bits.has_bits_remaining(2));
assert!(bits.has_bits_remaining(1));
}
#[test]
fn test_signed_bits_fast() {
let mut bits = LittleEndianReader::new(&[
0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39,
0xe7,
]);
for _ in 0..10 {
assert_eq!(bits.read_signed_bits(5), Some(-4));
}
}
#[test]
fn test_signed_bits2_fast() {
let mut bits =
LittleEndianReader::new(&[0xff, 0xdd, 0xee, 0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_signed_bits(10), Some(0x1ff));
assert_eq!(bits.read_signed_bits(10), Some(-73));
assert_eq!(bits.read_signed_bits(10), Some(-2));
assert_eq!(bits.read_signed_bits(10), Some(-137));
assert_eq!(bits.read_signed_bits(8), Some(-18));
assert_eq!(bits.read_signed_bits(8), Some(-86));
assert_eq!(bits.read_signed_bits(8), Some(-69));
assert_eq!(bits.read_signed_bits(8), Some(-52));
assert_eq!(bits.read_signed_bits(8), Some(-35));
assert_eq!(bits.read_bits(1), None);
}
#[test]
fn test_u8_reads() {
let mut bits = LittleEndianReader::new(&[0xff, 0xfe, 0xfa, 0xf7, 0xf5, 0xf0, 0xb1, 0xb2]);
assert_eq!(bits.read_u8(), Some(0xff));
assert_eq!(bits.read_u8(), Some(0xfe));
assert_eq!(bits.read_u8(), Some(0xfa));
assert_eq!(bits.read_u8(), Some(0xf7));
assert_eq!(bits.read_u8(), Some(0xf5));
assert_eq!(bits.read_u8(), Some(0xf0));
assert_eq!(bits.read_u8(), Some(0xb1));
assert_eq!(bits.read_u8(), Some(0xb2));
assert_eq!(bits.read_u8(), None);
}
#[test]
fn test_u32_bit_read() {
let mut bits = LittleEndianReader::new(&[0xff, 0x00, 0xab, 0xcd]);
assert_eq!(bits.read_bits(32), Some(0xcdab00ff));
}
#[test]
fn test_u32_reads() {
let mut bits = LittleEndianReader::new(&[
0xff,
0x00,
0xab,
0xcd,
0b1111_1110,
0b0000_0001,
0b0101_0110,
0b1001_1011,
0b0101_0101,
]);
assert_eq!(bits.read_u32(), Some(0xcdab00ff));
assert_eq!(bits.read_bit(), Some(false));
assert_eq!(bits.read_u32(), Some(0xcdab00ff));
assert_eq!(bits.read_bit(), Some(false));
assert_eq!(bits.read_u32(), None);
}
#[test]
fn test_f32_reads() {
let mut bits = LittleEndianReader::new(&[
0b0111_1011,
0b0001_0100,
0b1010_1110,
0b0011_1101,
0b1111_0110,
0b0010_1000,
0b0101_1100,
0b0111_1011,
0b0000_0010,
]);
assert_eq!(bits.read_f32(), Some(0.085));
assert_eq!(bits.read_bit(), Some(false));
assert_eq!(bits.read_f32(), Some(0.085));
}
#[test]
fn test_f64_reads() {
let mut bits = LittleEndianReader::new(&[0u8; 8]);
assert_eq!(bits.read_f64(), Some(0.0));
}
#[test]
fn test_u32_bits() {
let mut bits = LittleEndianReader::new(&[0xff, 0xdd, 0xee, 0xff, 0xdd, 0xee]);
assert_eq!(bits.read_bits(10), Some(0x1ff));
assert_eq!(bits.read_bits(10), Some(0x3b7));
assert_eq!(bits.read_bits(10), Some(0x3fe));
assert_eq!(bits.read_bits(10), Some(0x377));
assert_eq!(bits.read_bits(10), None);
}
#[test]
fn test_u32_bits2() {
let mut bits = LittleEndianReader::new(&[
0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39,
0xe7,
]);
for _ in 0..10 {
assert_eq!(bits.read_bits(5), Some(28));
}
}
#[test]
fn test_signed_bits2() {
let mut bits = LittleEndianReader::new(&[
0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39, 0xe7, 0x9c, 0x73, 0xce, 0x39,
0xe7,
]);
for _ in 0..10 {
assert_eq!(bits.read_signed_bits(5), Some(-4));
}
}
#[test]
fn test_approx_bytes_and_empty() {
let mut bits = LittleEndianReader::new(&[0xff, 0x04]);
assert!(!bits.is_empty());
assert_eq!(bits.bytes_remaining(), 2);
assert_eq!(bits.unbuffered_bytes_remaining(), 2);
assert!(bits.read_bit().is_some());
assert!(!bits.is_empty());
assert_eq!(bits.bytes_remaining(), 1);
assert_eq!(bits.unbuffered_bytes_remaining(), 0);
assert!(bits.read_bits(6).is_some());
assert!(!bits.is_empty());
assert_eq!(bits.bytes_remaining(), 1);
assert!(bits.read_bit().is_some());
assert!(!bits.is_empty());
assert_eq!(bits.bytes_remaining(), 1);
assert!(bits.read_bit().is_some());
assert!(!bits.is_empty());
assert_eq!(bits.bytes_remaining(), 0);
assert!(bits.read_bits(7).is_some());
assert!(bits.is_empty());
assert_eq!(bits.bytes_remaining(), 0);
}
#[test]
fn has_bits_remaining_max() {
let data = vec![];
let bits = LittleEndianReader::new(data.as_slice());
assert!(!bits.has_bits_remaining(usize::MAX));
}
#[test]
fn i16_test() {
let data = [0b1111_1111, 0b1111_1111];
let mut bits = LittleEndianReader::new(&data[..]);
assert_eq!(bits.read_i16(), Some(i16::from_le_bytes(data)));
}
#[test]
fn i16_min_test() {
let data = [0b0000_0000, 0b1000_0000];
let mut bits = LittleEndianReader::new(&data[..]);
assert_eq!(bits.read_i16(), Some(i16::MIN));
}
#[test]
fn i16_max_test() {
let data = [0b1111_1111, 0b0111_1111];
let mut bits = LittleEndianReader::new(&data[..]);
assert_eq!(bits.read_i16(), Some(i16::MAX));
}
#[test]
fn read_bits_52() {
let data = [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88];
let mut bits = LittleEndianReader::new(&data);
assert_eq!(bits.read_bits(4), Some(0xf));
assert_eq!(bits.read_bits(52), Some(0x99aabbccddeef));
}
#[test]
fn read_bits_56() {
let data: [u8; 8] = [0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89];
let mut bits = LittleEndianReader::new(&data);
assert_eq!(bits.read_bits(56), Some(0x67452301efcdab));
assert_eq!(bits.read_bits(4), Some(0x09));
}
#[test]
fn read_bits_64() {
let mut bits = LittleEndianReader::new(&[
0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45,
0x67, 0x89,
]);
assert_eq!(bits.read_bits(64), Some(0x8967452301efcdab));
assert_eq!(bits.read_bits(64), Some(0x8967452301efcdab));
}
#[test]
fn regression1() {
let data = vec![0b0000_0010, 0b0011_1111, 0b1011_1100];
let mut bits = LittleEndianReader::new(data.as_slice());
assert_eq!(bits.read_bits(3), Some(2));
assert_eq!(bits.read_u8(), Some(224));
assert_eq!(bits.read_bit(), Some(true));
assert_eq!(bits.read_bits(13), None);
}
#[test]
fn test_bytes_remaining() {
let mut bits = LittleEndianReader::new(&[0xff, 0x04]);
assert_eq!(bits.bytes_remaining(), 2);
assert_eq!(bits.unbuffered_bytes_remaining(), 2);
assert_eq!(bits.read_bit(), Some(true));
assert_eq!(bits.unbuffered_bytes_remaining(), 0);
assert_eq!(bits.bytes_remaining(), 1);
assert_eq!(bits.read_u8(), Some(0x7f));
assert!(bits.has_bits_remaining(7));
assert_eq!(bits.read_bits(7), Some(0x02));
}
#[test]
fn test_remainder_byte_aligned() {
let bits = LittleEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[0xaa, 0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_empty() {
let bits = LittleEndianReader::new(&[]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[]);
}
#[test]
fn test_remainder_after_reading_bits() {
let mut bits = LittleEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(3), Some(0x2));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x15);
assert_eq!(remainder.partial_bits(), 5);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_bit_count_in_partial_byte() {
let mut bits = LittleEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(3), Some(0x2));
let remainder = bits.remainder();
assert_eq!(remainder.partial_bits(), 5); assert_eq!(remainder.partial_byte(), 0x15); assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(2), Some(0x1));
let remainder = bits.remainder();
assert_eq!(remainder.partial_bits(), 3); assert_eq!(remainder.partial_byte(), 0x5); assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]); }
#[test]
fn test_remainder_simple_api() {
let bits = LittleEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[0xaa, 0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_empty_simple() {
let bits = LittleEndianReader::new(&[]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[]);
}
#[test]
fn test_remainder_with_partial_bits() {
let mut bits = LittleEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(3), Some(0x2));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x15);
assert_eq!(remainder.partial_bits(), 5);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(2), Some(0x1));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x5);
assert_eq!(remainder.partial_bits(), 3);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
}
}
#[cfg(test)]
mod be_tests {
use super::{BigEndianReader, BitReader};
#[test]
fn test_be_bit_bits_reads() {
let mut bits = BigEndianReader::new(&[0b1010_1010, 0b0101_0101]);
assert!(bits.has_bits_remaining(16));
assert_eq!(bits.bits_remaining(), Some(16));
assert_eq!(bits.read_bits(1), Some(1));
assert!(!bits.has_bits_remaining(16));
assert_eq!(bits.bits_remaining(), Some(15));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), Some(0));
assert_eq!(bits.read_bits(1), Some(1));
assert_eq!(bits.read_bits(1), None);
}
#[test]
fn test_zero_bit_reads() {
let mut bits = BigEndianReader::new(&[0xff]);
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.read_bits(0), Some(0));
assert_eq!(bits.read_u8(), Some(0xff));
assert_eq!(bits.read_bits(0), Some(0));
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.peek(0), 0);
bits.consume(0);
assert_eq!(bits.read_bits(0), Some(0));
}
#[test]
fn test_whole_bytes() {
let mut bits = BigEndianReader::new(&[
0xff, 0xdd, 0xee, 0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd, 0xff, 0xdd, 0xee, 0xff,
0xdd,
]);
assert_eq!(bits.read_u8(), Some(0xff));
assert_eq!(bits.read_u16(), Some(u16::from_be_bytes([0xdd, 0xee])));
let mut out = [0u8; 8];
assert!(bits.read_bytes(&mut out));
assert_eq!(
u64::from_be_bytes(out),
u64::from_be_bytes([0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd, 0xff])
);
assert_eq!(
bits.read_u32(),
Some(u32::from_be_bytes([0xdd, 0xee, 0xff, 0xdd]))
);
}
#[test]
fn test_whole_bytes_shift() {
let mut bits = BigEndianReader::new(&[
0xdf, 0xed, 0xfe, 0xdf, 0xed, 0xae, 0xba, 0xcb, 0xdc, 0xfd, 0xdf, 0xed, 0xfe, 0xdf,
0x0d,
]);
assert_eq!(bits.read_bits(4), Some(0x0d));
assert_eq!(bits.read_u16(), Some(u16::from_be_bytes([0xfe, 0xdf])));
let mut out = [0u8; 8];
assert!(bits.read_bytes(&mut out));
assert_eq!(
u64::from_be_bytes(out),
u64::from_be_bytes([0xed, 0xfe, 0xda, 0xeb, 0xac, 0xbd, 0xcf, 0xdd])
);
assert_eq!(
bits.read_u32(),
Some(u32::from_be_bytes([0xfe, 0xdf, 0xed, 0xf0]))
);
}
#[test]
fn test_whole_bytes_trailing() {
let mut bits =
BigEndianReader::new(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01]);
assert!(bits.read_bytes(&mut [0]));
assert_eq!(bits.read_bits(0), Some(0));
}
#[test]
fn test_whole_bytes_large() {
let mut data = vec![0u8; 76];
data[0] = 0b0000_0101;
data[6] = 0b0000_1000;
data[7] = 0b0000_0010;
data[8] = 0b0000_0011;
data[28] = 0b0000_0000;
data[29] = 0b1111_1111;
data[74] = 0b1000_0000;
data[75] = 0b1011_1111;
let mut bitter = BigEndianReader::new(&data);
assert_eq!(bitter.read_bit(), Some(false));
let mut buf = [0u8; 75];
assert!(bitter.read_bytes(&mut buf));
assert_eq!(buf[0], 0b0000_1010);
assert_eq!(buf[6], 0b0001_0000);
assert_eq!(buf[7], 0b0000_0100);
assert_eq!(buf[8], 0b0000_0110);
assert_eq!(buf[28], 0b0000_0001);
assert_eq!(buf[74], 0b0000_0001);
assert_eq!(bitter.read_bits(7), Some(0b0011_1111));
assert_eq!(bitter.read_bit(), None);
}
#[test]
fn test_u32_bits() {
let mut bits =
BigEndianReader::new(&[0xff, 0xdd, 0xee, 0xff, 0xdd, 0xee, 0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(10), Some(0b11_1111_1111));
assert_eq!(bits.read_bits(10), Some(0b01_1101_1110));
assert_eq!(bits.read_bits(10), Some(0b11_1011_1111));
assert_eq!(bits.read_bits(10), Some(0b11_1101_1101));
assert_eq!(bits.read_bits(8), Some(0xee));
assert_eq!(bits.read_bits(8), Some(0xaa));
assert_eq!(bits.read_bits(8), Some(0xbb));
assert_eq!(bits.read_bits(8), Some(0xcc));
assert_eq!(bits.read_bits(8), Some(0xdd));
assert_eq!(bits.read_bit(), None);
}
#[test]
fn test_u32_bits2() {
let mut bits = BigEndianReader::new(&[
0b1110_0111,
0b0011_1001,
0b1100_1110,
0b0111_0011,
0b1001_1100,
0b1110_0111,
0b0011_1001,
0b1100_1110,
0b0111_0011,
0b1001_1100,
]);
for _ in 0..16 {
assert_eq!(bits.read_bits(5), Some(28));
}
}
#[test]
fn test_u32_bit_read() {
let mut bits = BigEndianReader::new(&[0xff, 0x00, 0xab, 0xcd]);
assert_eq!(bits.read_bits(32), Some(0xff00abcd));
}
#[test]
fn read_bits_52() {
let data = [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88];
let mut bits = BigEndianReader::new(&data);
assert_eq!(bits.read_bits(4), Some(0xf));
assert_eq!(bits.read_bits(52), Some(0xfeeddccbbaa99));
}
#[test]
fn read_bits_64() {
let mut bits = BigEndianReader::new(&[
0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45,
0x67, 0x89,
]);
assert_eq!(bits.read_bits(64), Some(0xabcdef0123456789));
assert_eq!(bits.read_bits(64), Some(0xabcdef0123456789));
}
#[test]
fn test_signed_bits() {
let mut bits = BigEndianReader::new(&[0xe7, 0x39, 0xce, 0x73, 0x9C, 0xE7, 0x39, 0xC0]);
for _ in 0..12 {
assert_eq!(bits.read_signed_bits(5), Some(-4));
}
}
#[test]
fn test_remainder_byte_aligned() {
let bits = BigEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[0xaa, 0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_empty() {
let bits = BigEndianReader::new(&[]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[]);
}
#[test]
fn test_remainder_after_reading_bits() {
let mut bits = BigEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(3), Some(0x5));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x0a);
assert_eq!(remainder.partial_bits(), 5);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_simple_api() {
let bits = BigEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[0xaa, 0xbb, 0xcc, 0xdd]);
}
#[test]
fn test_remainder_empty_simple() {
let bits = BigEndianReader::new(&[]);
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0);
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[]);
}
#[test]
fn test_remainder_with_partial_bits() {
let mut bits = BigEndianReader::new(&[0xaa, 0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(3), Some(0x5));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x0a);
assert_eq!(remainder.partial_bits(), 5);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
assert_eq!(bits.read_bits(2), Some(0x1));
let remainder = bits.remainder();
assert_eq!(remainder.partial_byte(), 0x2);
assert_eq!(remainder.partial_bits(), 3);
assert_eq!(remainder.data(), &[0xbb, 0xcc, 0xdd]);
}
}