Expand description
bnb — an owned, bit-aware binary codec: ergonomic, fast bit/byte field types and
the unified #[bin] whole-message codec.
It provides, designed to compose:
- Arbitrary-width integers (
u1..u127, viaUInt) for sub-byte fields — a dependency-free replacement forarbitrary-int. #[bitfield]— an attribute macro that packs typed fields into a single backing integer with explicit, independent control of bit order (MSB/LSB-first) and byte order (big/little). It generates getters, immutablewith_*setters, raw access, and allocation-free*_bytesconversions.#[derive(BitEnum)]— enum ⇄ integer at a chosen width, with an optional#[catch_all]variant that preserves unknown values (the dual-use convention).#[bin]— the unified whole-message codec (see below): reads/writes a struct at arbitrary bit offsets, with a rich,binrw-inspired directive surface.
The aim is to collapse a whole stack of overlapping helpers —
modular-bitfield(-msb), bitfield-struct, bitbybit, arbitrary-int,
num_enum, and a binrw-style codec — into one fast, integer-backed
(shift/mask, no bitvec) crate. See Inspiration.
§Example — a DNS-style 16-bit header field
use bnb::{bitfield, BitEnum, u4, u5, u7};
#[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
#[bit_enum(u4)]
enum RCode {
NoError, // 0
FormErr, // 1
ServFail, // 2
#[catch_all]
Other(u4), // any other 4-bit value
}
// MSB-first packing (network/RFC order), big-endian on the wire.
#[bitfield(u16, bits = msb, bytes = be)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct State {
opcode: u5, // first field -> high bits
flags: Flags,
rcode: RCode, // last field -> low bits
}
let s = State::new()
.with_opcode(u5::new(2))
.with_rcode(RCode::ServFail);
assert_eq!(s.rcode(), RCode::ServFail);
// opcode occupies bits 11..=15 (the high 5 of the u16).
assert_eq!(s.to_be_bytes()[0] >> 3, 2);§Bit order vs. byte order
These are independent knobs, which is the whole point:
bits = msb | lsb— does the first declared field land in the high or low bits of the backing integer. Default:msb(matches RFC ASCII-art layouts).bytes = be | le— endianness of the backing integer when serialized. Default:be.
§The #[bin] codec
Whole-message bit-aware codec: #[bin] (magic/count/ctx/map/if/calc·temp/reserved/
positioning/validate) over a Source/SeekSource/BufSource/SeekReader I/O
ladder, with an opt-in bytes feature for async framing.
§Feature flags & no_std
bnb is no_std-compatible — it always needs alloc (the codec produces
Vec<u8> and owns variable-length payloads), but not std. Build with
default-features = false for an embedded target.
std(default) — thestd::ioladder (StreamBitReader,BufSource,SeekReader,Source::as_read/Sink::as_write), theFrom<std::io::Error>bridge, and theencode(writer)/spec_encode(writer)conveniences (EncodeExt/SpecEncodeExt). The#[br(dbg)]directive (which emits atracingevent) is alsostd-only.bytes— the zero-copybytes-crate adapters; impliesstd(async/tokio framing).
Without std you still get the full macro surface plus: decode from a &[u8]
(BitReader, Type::decode/decode_exact/peek/decode_from) and encode to a
Vec<u8> (Type::to_bytes/to_spec_bytes, encode_into over a Sink). You lose
only the streaming std::io adapters and encode(&mut impl Write); on no_std,
encode with to_bytes() and write the bytes to your transport yourself.
§Inspiration
bnb stands on the shoulders of several excellent crates, collapsing their
capabilities into one: the arbitrary-width integers of arbitrary-int; the
bitfield packing of modular-bitfield, bitfield-struct, and bitbybit; the
enum ⇄ integer mapping of num_enum; and — most of all — the declarative,
bidirectional codec design of binrw,
whose #[br]/#[bw] attribute vocabulary #[bin] deliberately echoes so the two
feel like one toolkit. bnb shares no code with these crates; it is a from-scratch
implementation, extended to do the one thing a byte-oriented Read + Seek codec
cannot: read and write fields at arbitrary bit offsets. See ACKNOWLEDGMENTS.md
for the full credit.
§Guide
The guide module is a set of worked, runnable walkthroughs — start there for a
tour of the crate and the rationale behind each piece. Reading order:
guide::quick_start— a five-minute tour of every macro.guide::numbers— the arbitrary-width integers (u1..u127) and theBitstrait that lets everything compose.guide::bitfields—#[bitfield]: bit order, byte order, widths and ranges, nesting.guide::enums—#[derive(BitEnum)]: catch-all vs. closed,num_enumparity.guide::flags—#[bitflags]: single-bit flag sets with set algebra.guide::builders—#[derive(BitsBuilder)]: the required-by-default builder.guide::bin_codec—#[bin]: a whole protocol header, end to end.guide::directives— the field-directive reference, one example each.guide::dispatch—#[bin]on an enum: tagged-union dispatch by wiremagicor off-wiretag.guide::io— theSource/SinkI/O ladder (slice, stream, socket, file,bytes).guide::errors— position-aware errors and the streamingIncompletesignal.guide::dual_use— the compliant-by-default-but-violatable philosophy.guide::composition— how the pieces nest and size each other.
Re-exports§
pub use bitstream::BitAmount;pub use bitstream::BitDecode;pub use bitstream::BitEncode;pub use bitstream::BitError;pub use bitstream::BitReader;pub use bitstream::BitWriter;pub use bitstream::DecodeWith;pub use bitstream::EncodeWith;pub use bitstream::ErrorKind;pub use bitstream::FixedBitLen;pub use bitstream::Layout;pub use bitstream::SeekSource;pub use bitstream::Sink;pub use bitstream::Source;pub use bitstream::SpecEncode;pub use bitstream::BufSource;pub use bitstream::EncodeExt;pub use bitstream::SeekReader;pub use bitstream::SinkWriter;pub use bitstream::SourceReader;pub use bitstream::SpecEncodeExt;pub use bitstream::StreamBitReader;pub use builder::BuilderError;pub use error::Error;pub use error::Result;pub use error::UnknownDiscriminant;pub use int::UInt;pub use int::*;
Modules§
- bitstream
- A bit-level stream codec — read/write fields at arbitrary bit offsets, not just byte boundaries.
- builder
- Support types for
#[derive(BitsBuilder)]and#[bin]. - error
- The crate’s error type and result alias.
- guide
- The
bnbguide — worked, runnable walkthroughs. - int
- Arbitrary-width unsigned integers (
u1..u127) — the substrate for sub-byte bitfield fields. Replaces thearbitrary-intdependency. - prelude
- Common imports for the codec — the typed positioning amounts (
4.bits(),3.bytes()) used by#[br(pad_before = …)]etc., plus the encode extension traits that carryencode(writer)/spec_encode(writer)(thestdfeature).
Enums§
- BitOrder
- Bit packing order within a bitfield: does the first declared field occupy the most-significant or least-significant bits of the backing integer.
- Byte
Order - Byte order of a bitfield’s backing integer when it is serialized.
Traits§
- BitEnum
- Marker trait implemented by
#[derive(BitEnum)]enums: aBitsvalue whose representation is an integer discriminant of a fixed width. - Bitfield
- The seam every
#[bitfield]struct implements — the stable interface the#[bin]codec builds on, independent of how the fields are accessed. - Bits
- A value that occupies a fixed number of bits within a bitfield.
Attribute Macros§
- bin
#[bin]— the unified whole-message bit codec. One attribute that folds the read codec (BitDecode), the write codec (BitEncode), and a required-by-default builder (BitsBuilder) over a struct ofbnb::Bitsfields, read and written at arbitrary bit offsets.- bitfield
- Packs the annotated struct’s fields into a single backing integer.
- bitflags
- Packs named single-bit flags into one backing integer, with set algebra.
Derive Macros§
- BitDecode
- Derives a
bnb::BitDecodeimpl that reads the struct’s named fields, in declaration order, from a bit cursor (abnb::BitReader). - BitEncode
- Derives a
bnb::BitEncodeimpl — the dual ofBitDecode, writing the struct’s named fields in order to abnb::BitWriterbit cursor. SharesBitDecode’s right-tool guard and#[bit_stream(...)]override. - BitEnum
- Derives an enum ⇄ integer mapping of a fixed bit width.
- Bits
Builder - Generates a
derive_builder-style builder for a struct (or, when listed in a#[bitfield]’s derives, for the bitfield — intercepted by#[bitfield]).