BitReader

Trait BitReader 

Source
pub trait BitReader {
Show 26 methods // Required methods 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; fn remainder(&self) -> Remainder<'_>;
}
Expand description

Read bits in a given endian order

Required Methods§

Source

fn read_bit(&mut self) -> Option<bool>

Consume a bit and return if the bit was enabled

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0b1001_0011]);
assert_eq!(bits.read_bit(), Some(true));
assert_eq!(bits.read_bit(), Some(false));
Source

fn read_u8(&mut self) -> Option<u8>

Consume 8 bits and return the deserialized byte

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0b1001_0011]);
assert_eq!(bits.read_u8(), Some(0b1001_0011));
Source

fn read_i8(&mut self) -> Option<i8>

Consume 8 bits and return the deserialized byte

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0b1001_0011]);
assert_eq!(bits.read_i8(), Some(-109));
Source

fn read_u16(&mut self) -> Option<u16>

Consume 16 bits and return the deserialized short

use bitter::{BitReader, LittleEndianReader};
let mut bits = LittleEndianReader::new(&[0b1001_0011, 0b1111_1111]);
assert_eq!(bits.read_u16(), Some(0xff93));
Source

fn read_i16(&mut self) -> Option<i16>

Consume 16 bits and return the deserialized short

use bitter::{BitReader, LittleEndianReader};
let data = (-500i16).to_le_bytes();
let mut bits = LittleEndianReader::new(&data);
assert_eq!(bits.read_i16(), Some(-500));
Source

fn read_u32(&mut self) -> Option<u32>

Consume 32 bits and return the deserialized int

use bitter::{BitReader, LittleEndianReader};
let data = (22000u32).to_le_bytes();
let mut bits = LittleEndianReader::new(&data);
assert_eq!(bits.read_u32(), Some(22000u32));
Source

fn read_i32(&mut self) -> Option<i32>

Consume 32 bits and return the deserialized int

use bitter::{BitReader, BigEndianReader};
let data = (-22000i32).to_be_bytes();
let mut bits = BigEndianReader::new(&data);
assert_eq!(bits.read_i32(), Some(-22000i32));
Source

fn read_f32(&mut self) -> Option<f32>

Consume 32 bits and return the deserialized floating point

use bitter::{BitReader, BigEndianReader};
let data = 12.5f32.to_be_bytes();
let mut bits = BigEndianReader::new(&data);
assert_eq!(bits.read_f32(), Some(12.5f32));
Source

fn read_u64(&mut self) -> Option<u64>

Consume 64 bits and return the deserialized int

use bitter::{BitReader, LittleEndianReader};
let data = (22000u64).to_le_bytes();
let mut bits = LittleEndianReader::new(&data);
assert_eq!(bits.read_u64(), Some(22000u64));
Source

fn read_i64(&mut self) -> Option<i64>

Consume 64 bits and return the deserialized int

use bitter::{BitReader, BigEndianReader};
let data = (-22000i64).to_be_bytes();
let mut bits = BigEndianReader::new(&data);
assert_eq!(bits.read_i64(), Some(-22000i64));
Source

fn read_f64(&mut self) -> Option<f64>

Consume 64 bits and return the deserialized floating point

use bitter::{BitReader, BigEndianReader};
let data = 12.5f64.to_be_bytes();
let mut bits = BigEndianReader::new(&data);
assert_eq!(bits.read_f64(), Some(12.5f64));
Source

fn read_bits(&mut self, bits: u32) -> Option<u64>

Reads an arbitrary number of bits in the range of [0, 64] and returns the unsigned result

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0xff, 0x00, 0xab, 0xcd]);
assert_eq!(bits.read_bits(32), Some(0xff00abcd));
Source

fn read_signed_bits(&mut self, bits: u32) -> Option<i64>

Reads an arbitrary number of bits in the range of [0, 64] and returns the signed result.

If the most significant bit is enabled, the result will be negative. This can be somewhat counterintuitive so see the examples

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0xfa, 0x93]);
assert_eq!(bits.read_signed_bits(4), Some(-1));
assert_eq!(bits.read_signed_bits(4), Some(-6));
assert_eq!(bits.read_signed_bits(4), Some(-7));
assert_eq!(bits.read_signed_bits(4), Some(3));

To think of it another way, reading the number of bits equivalent to a builtin type (i8, i16, etc), will always equal its associated ergonomic equivalent when casted.

use bitter::{BitReader, BigEndianReader};
let mut bits = BigEndianReader::new(&[0xff]);
let mut bitter2 = BigEndianReader::new(&[0xff]);
assert_eq!(
    bits.read_signed_bits(8).map(|x| x as i8),
    bitter2.read_i8()
);
Source

fn bytes_remaining(&self) -> usize

Returns how many complete bytes are left in the bitstream.

let mut bits = LittleEndianReader::new(&[0xff]);
assert_eq!(bits.bytes_remaining(), 1);
assert!(bits.read_bit().is_some());
assert_eq!(bits.bytes_remaining(), 0);
assert!(bits.read_bits(7).is_some());
assert_eq!(bits.bytes_remaining(), 0);
Source

fn unbuffered_bytes_remaining(&self) -> usize

Returns how many bytes are still left in the passed in buffer.

How many bytes remain in the original buffer is typically an implementation detail, and one should prefer BitReader::bytes_remaining, which includes bytes in the lookahead buffer.

However, the bitter unchecked API, BitReader::refill_lookahead_unchecked, requires this same calculation to avoid undefined behavior.

Anecdotally the use of this function can assist the compiler in eliminating branches that would appear in BitReader::refill_lookahead without needing to introduce unsafe blocks. Your mileage may vary.

let mut bits = LittleEndianReader::new(&[0u8; 100]);
if bits.unbuffered_bytes_remaining() >= 16 {
  // The compiler can eliminate the end of buffer checks
  // in both of these refills without needing to drop to unsafe
  bits.refill_lookahead();
  // ... do some reading ...
  bits.refill_lookahead();
}
Source

fn bits_remaining(&self) -> Option<usize>

Returns the exact number of bits remaining in the bitstream if the number of bits can fit within a usize. For large byte slices, calculating the number of bits can cause an overflow, hence an Option is returned. See has_bits_remaining for a more robust, performant, and ergonomic alternative.

let mut bits = LittleEndianReader::new(&[0xff]);
assert_eq!(bits.bits_remaining(), Some(8));
assert!(bits.read_bit().is_some());
assert_eq!(bits.bits_remaining(), Some(7));
assert!(bits.read_bits(7).is_some());
assert_eq!(bits.bits_remaining(), Some(0));
Source

fn has_bits_remaining(&self, bits: usize) -> bool

Returns true if at least bits number of bits are left in the stream. A more robust, performant, and ergonomic way than bits_remaining.

let mut bits = LittleEndianReader::new(&[0xff]);
assert!(bits.has_bits_remaining(7));
assert!(bits.has_bits_remaining(8));
assert!(!bits.has_bits_remaining(9));

assert!(bits.read_bit().is_some());
assert!(bits.has_bits_remaining(7));
assert!(!bits.has_bits_remaining(8));

assert!(bits.read_bits(7).is_some());
assert!(!bits.has_bits_remaining(7));
assert!(bits.has_bits_remaining(0));
Source

fn read_bytes(&mut self, buf: &mut [u8]) -> bool

Read the number of bytes needed to fill the provided buffer. Returns whether the read was successful and the buffer has been filled. If there aren’t enough bytes remaining, then the bit stream and buffer remains unchanged

let mut bits = LittleEndianReader::new(&[0b1010_1010, 0b0101_0101]);
let mut buf = [0; 1];
assert_eq!(bits.read_bit(), Some(false));
assert!(bits.read_bytes(&mut buf));
assert_eq!(&buf, &[0b1101_0101]);
assert!(!bits.read_bytes(&mut buf));
assert_eq!(bits.read_bits(1), Some(0));
Source

fn is_empty(&self) -> bool

Returns if the bitstream has no bits left

let mut bits = LittleEndianReader::new(&[0b1010_1010, 0b0101_0101]);
assert_eq!(bits.is_empty(), false);
assert_eq!(bits.read_u16(), Some(0b0101_0101_1010_1010));
assert_eq!(bits.is_empty(), true);
Source

fn peek(&self, count: u32) -> u64

Peeks at the given number of bits in the lookahead buffer

It is invalid to peek at more than what was returned in the last refill

A core tenent of Manual Mode: refill / peek / consume

Source

fn consume(&mut self, count: u32)

Consumes the number of bits from the lookahead buffer

A core tenent of Manual Mode: refill / peek / consume

Source

fn refill_lookahead(&mut self)

Refills the lookahead buffer.

A core tenent of Manual Mode: refill / peek / consume

Refills the lookahead buffer anywhere between [MAX_READ_BITS, 64] as long as the end of the stream has not been reached. See how many bits are in the buffer with BitReader::lookahead_bits.

If BitReader::lookahead_bits is already in the specified range, additional refills will have no effect.

Source

fn lookahead_bits(&self) -> u32

Returns the number of bits in the lookahead buffer

These are the number of bits available to be consumed before a refill is necessary.

Guaranteed to be between [MAX_READ_BITS, 64] when at least 8 bytes of data remains unread.

Source

unsafe fn refill_lookahead_unchecked(&mut self)

Refills the lookahead buffer without bounds checking

After calling, the lookahead buffer is guaranteed to have between [MAX_READ_BITS, 64] bits available to read.

§Safety

This function assumes that there are at least 8 bytes left unbuffered for an unaligned read. It is undefined behavior if there is less than 8 bytes remaining

Guard all usages with BitReader::unbuffered_bytes_remaining

let mut bits = LittleEndianReader::new(&[0u8; 100]);
let objects_to_read = 7;
let object_bits = 39;
let desired_bits = objects_to_read * object_bits;
let bytes_needed = (desired_bits as f64 / 8.0).ceil();
if bits.unbuffered_bytes_remaining() >= bytes_needed as usize {
  for _ in 0..objects_to_read {
    unsafe { bits.refill_lookahead_unchecked() };
    let _field1 = bits.peek(10);
    bits.consume(10);

    let _field2 = bits.peek(29);
    bits.consume(29);
  }
}
Source

fn byte_aligned(&self) -> bool

Returns true if the reader is not partway through a byte

let mut bits = LittleEndianReader::new(&[0b1010_1010, 0b0101_0101]);
let mut buf = [0; 1];
assert!(bits.byte_aligned());
assert_eq!(bits.read_bit(), Some(false));
assert!(!bits.byte_aligned());
Source

fn remainder(&self) -> Remainder<'_>

Returns the remainder of unread data.

let mut bits = LittleEndianReader::new(&[0b1010_1010, 0b0101_0101, 0b1100_0011]);

// When byte-aligned, no partial bits
let remainder = bits.remainder();
assert_eq!(remainder.partial_bits(), 0);
assert_eq!(remainder.data(), &[0b1010_1010, 0b0101_0101, 0b1100_0011]);

// After reading 3 bits, we have 5 bits remaining in a partially read byte
assert_eq!(bits.read_bits(3), Some(0b010));
let remainder = bits.remainder();

assert_eq!(remainder.partial_bits(), 5);
assert_eq!(remainder.partial_byte(), 0b0001_0101);
assert_eq!(remainder.data(), &[0b0101_0101, 0b1100_0011]);

Implementors§