Expand description
A bit-level stream codec — read/write fields at arbitrary bit offsets, not just byte boundaries.
A byte-oriented Read + Seek codec can only address byte boundaries, so a field
that starts mid-byte (a 108-bit DMR payload, a 48-bit sync pattern) forces
hand-rolled backward seeks and nibble shifts.
BitReader/BitWriter track a bit cursor over a byte buffer and
read/write any Bits value (u1..u127, #[bitfield], #[derive(BitEnum)])
directly — bit-aware and fast (shift/mask, no bitvec).
The wire Layout is configurable: bit order (MSB-first default — bit 0 is the
high bit of byte 0, the RFC/ETSI convention — or LSB-first) and byte order (big-
endian default, or little-endian for byte-multiple values).
use bnb::{u4, u12, BitReader, BitWriter};
// Pack a 4-bit then a 12-bit field into a 16-bit (2-byte) stream.
let mut w = BitWriter::new();
w.write(u4::new(0xA)).unwrap();
w.write(u12::new(0xBCD)).unwrap();
let bytes = w.into_bytes();
assert_eq!(bytes, [0xAB, 0xCD]);
let mut r = BitReader::new(&bytes);
assert_eq!(r.read::<u4>().unwrap(), u4::new(0xA));
assert_eq!(r.read::<u12>().unwrap(), u12::new(0xBCD));Structs§
- BitBuf
- A push/pull, bit-aware decode buffer for incremental framing.
- BitError
- A position-aware bit-codec error (it carries a span-like position). It records the bit offset where decoding/encoding failed and, when the derive can supply it, the field being processed.
- BitReader
- A cursor that reads values at arbitrary bit offsets from a byte slice, in a
chosen
BitOrder(MSB-first by default —bit 0is the high bit of byte 0, the RFC/ETSI ASCII-art convention; LSB-first for serial/PHY layers). - BitWriter
- A sink that appends values at arbitrary bit offsets in a chosen
BitOrder(MSB-first by default), growing a byte buffer (the final partial byte is zero-padded). - BufSource
std - A seekable
Sourceover a forwardRead(a socket): it retains the bytes it has read, so a seek-using message (restore_position) works over a non-seekable stream by seeking within the retained buffer, reading more on demand. It is bounded — a retentioncap(default 64 KiB) past which it errorsErrorKind::BufferFullrather than buffering unboundedly. The “continuously-receiving peer that also needs to seek” case. - Bytes
Reader bytes - A
SeekSourcethat owns abytes::Bytesframe (no borrow), decoding bits from it. Constructing it from aBytesis a refcount bump (zero copy). - Bytes
Writer bytes - A
Sinkthat encodes into abytes::BytesMut;freezehands off a zero-copyBytes. - Capacity
Error - The error
BitBuf::try_pushreturns when bytes won’t fit aboundedbuffer — the live (unconsumed) bytes plus the new bytes exceed its fixedcap. Grow it withBitBuf::grow, or drain messages withpullbefore pushing more. - Layout
- The wire layout: bit packing order and byte order, threaded through the
cursors and entry points.
#[bin(big|little)]and#[bin(bits = msb|lsb)]set it; the default is MSB-first, big-endian (RFC/network order). - Seek
Reader std - A
SeekSourceover a seekable reader (Read + Seek, e.g. aFile): it seeks viastd::io::Seekto the byte holding the bit cursor, without buffering — the large-file / container-format case. For a non-seekable stream that still needs to seek, useBufSource. - Sink
Writer std - A
std::io::Writeview over aSink, fromSink::as_write. Eachwritepushes 8 bits per byte throughSink::write_bits. The outbound dual ofSourceReader;flushis a no-op (the sink owns its buffer). - Source
Reader std - A
std::io::Readview over aSource, fromSource::as_read. Eachreadpulls 8 bits per byte throughSource::read_bits, so it works at any bit alignment (you will normally be byte-aligned). A read failure surfaces as anio::Errorwhen no bytes were produced, or ends the read short once some were — thestd::ioconvention. This is the outbound dual ofBufSource/SeekReader(which adapt astd::io::Readinto aSource). - Stream
BitReader std - A forward-only bit reader over any
std::io::Read— the streaming counterpart to the in-memoryBitReader, for a stream you read once and don’t seek.
Enums§
- Error
Kind - The cause of a
BitError.#[non_exhaustive]: new variants may be added without a major version bump, so match with a wildcard arm.
Traits§
- BitAmount
- A typed bit/byte amount for positioning directives —
4.bits(),3.bytes()— resolving to a bit count. Bring it in withuse bnb::prelude::*. - BitDecode
- A message decoded from a bit stream — the recursion point a
#[derive(BitDecode)]struct implements (reading each field in declaration order). Leaf fields are anyBitstype; nested messages recurse. Fixed- or variable-length; a fixed-length message also implementsFixedBitLen. - BitEncode
- A message encoded to a bit stream — the dual of
BitDecode. - Count
Prefix - Checked length ⇄ wire-prefix conversions: the types usable as a length/count prefix —
by the
#[brw(count_prefix = <Ty>)]directive and by thecodecs::prefixedstring codec. - Decode
With - Polymorphic decode with context
A— the companion to a#[bin(ctx(...))]type’s inherentdecode_with, for hand-written generic combinators and trait-object parsing (ctx Layer 2). EveryBitDecodetype isDecodeWith<()>(blanket), and a ctx type isDecodeWith<…Ctx>, so one boundT: DecodeWith<A>spans both context-free and context-taking messages. InherentType::decode_withcall sites are unaffected. - Encode
Ext std encode(writer)for anyBitEncodemessage — encodes to aVec(using the type’sLAYOUT) verbatim and writes it to astd::io::Writesink. A blanket-implemented extension trait, so bring it into scope (use bnb::prelude::*oruse bnb::EncodeExt) to call.encode(&mut w). Only with thestdfeature; inno_stduse the generatedto_bytes/to_canonical_bytes, orbit_encode/canonical_bit_encodeover aSink.- Encode
With - The dual of
DecodeWith— polymorphic encode with contextA. - Fixed
BitLen - A message whose encoded length is a compile-time constant — i.e. it has no
variable-length (
count-drivenVec) field. The derive implements this only for fixed messages; it sizes a fixed byte region when the message is embedded as a field in another message (its contribution to the parent’s width). Acount-bearing message implementsBitDecode/BitEncodebut not this.Bitsleaves also implement it (theirBIT_LENisBits::BITS), so a field’s width is computed uniformly whether it’s a leaf or a nested message. - Seek
Source - A
Sourcethat can seek (itsseek_to_bitis real, not the failing default). A#[bin]message that usesrestore_positionbounds its generateddecodeon this trait, so a forward-only stream is rejected at compile time. Implemented byBitReader,BufSource, andSeekReader(and, with thebytesfeature,BytesReader). - Sink
- A bit-level output the codec writes to — the in-memory
BitWriter(and, under thebytesfeature,BytesWriter). Encode to anystd::io::Writevia a message’s generatedencodemethod. - Source
- A bit-level input the codec recurses over. Implemented by
BitReader(in-memory slice),StreamBitReader(forwardRead),BufSource(a retain-and-seek socket adapter), andSeekReader(Read + Seek); the codec is generic overSource, so one decoder runs over any of them — seeguide::io.