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§
- 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
- 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. - Layout
- The wire layout: bit packing order and byte order, threaded through the
cursors and entry points.
#[bin(big|little)]and#[bin(bit_order = msb|lsb)]set it; the default is MSB-first, big-endian (RFC/network order). - Seek
Reader - 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 - 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 - 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 - 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§
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. - 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 encode(writer)for anyBitEncodemessage — encodes to aVec(using the type’sLAYOUT) 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 available with thestdfeature; inno_stduseBitEncode’s generatedto_bytes/encode_into.- 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 in a byte stream (e.g. a#[nested]field’s contribution to its parent’s width). Acount-bearing message implementsBitDecode/BitEncodebut not this. - Seek
Source - A
Sourcethat can seek (itsseek_to_bitis real, not the failing default). A#[bin]message that usesrestore_positionbounds its generateddecode_fromon 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. - Spec
Encode - The “write reserved fields as their spec value” encode path, generated for a
#[bin]message that has areservedfield. The inherentto_spec_bytes/spec_encode_intoride on this; thestd-onlySpecEncodeExtaddsspec_encode(writer). - Spec
Encode Ext spec_encode(writer)for anySpecEncodemessage — the spec-value dual ofEncodeExt. Blanket-implemented; bring it into scope to call it. Only with thestdfeature; inno_stduse the generatedto_spec_bytes.