Crate bitter [−] [src]
Bitter takes a slice of byte data and reads little-endian bits platform agonistically. Bitter has been optimized to be fast for reading 64 or fewer bits at a time, though it can still extract an arbitrary number of bytes.
There are two main APIs available: checked and unchecked functions. A checked function will
return a Option
that will be None
if there is not enough bits left in the stream.
Unchecked functions, which are denoted by having "unchecked" in their name, will panic if there
is not enough data left, but happen to be ~10% faster (your numbers
will vary depending on use case).
Tips:
- Prefer checked functions for all but the most performance critical code
- Group all unchecked functions in a single block guarded by a
approx_bytes_remaining
orbits_remaining
call - Prefer
read_u8()
overread_u32_bits_unchecked(8)
as the specialized functions have a slight performance edge over the generic function
Example
use bitter::BitGet; let mut bitter = BitGet::new(&[0xff, 0x04]); assert_eq!(bitter.read_bit(), Some(true)); assert_eq!(bitter.read_u8(), Some(0x7f)); assert_eq!(bitter.read_u32_bits(7), Some(0x02));
Below, is a demonstration of guarding against potential panics:
let mut bitter = BitGet::new(&[0xff, 0x04]); if bitter.approx_bytes_remaining() >= 2 { assert_eq!(bitter.read_bit_unchecked(), true); assert_eq!(bitter.read_u8_unchecked(), 0x7f); assert_eq!(bitter.read_u32_bits_unchecked(7), 0x02); }
Another guard usage. bits_remaining
is more accurate but involves a 3 operations to
calculate.
let mut bitter = BitGet::new(&[0xff, 0x04]); if bitter.bits_remaining() >= 16 { for _ in 0..8 { assert_eq!(bitter.read_bit_unchecked(), true); } assert_eq!(bitter.read_u8_unchecked(), 0x04); }
Implementation
Currently the implementation pre-fetches 64 bit chunks so that more operations can be performed
on a single primitive type (u64
). Pre-fetching like this allows for operations that request
4 bytes to be completed in, at best, a bit shift and mask instead of, at best, four bit
shifts and masks.
Comparison to other libraries
Bitter is hardly the first Rust library for handling bits. bitstream_io and bitreader are both crates one should consider. The reason why someone would choose bitter over those two is speed. The other libraries lack a "trust me I know what I'm doing" API, which bitter can give you a 10x performance increase. Additionally, some libraries favor byte aligned reads (looking at you, bitstream_io), and since 7 out of 8 bits aren't byte aligned, there is a performance hit.
Structs
BitGet |
Yields consecutive bits as little endian primitive types |