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 = big)]
#[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 = big | 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. Common field codecs —
LEB128 varints, NUL-terminated and length-prefixed strings — ship ready-made in
codecs (referenced via parse_with/write_with).
§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)convenience (EncodeExt). The#[br(dbg)]directive (which emits atracingevent) is alsostd-only.bytes— the zero-copybytes-crate adapters; impliesstd(async/tokio framing).tokio—BinCodec, atokio_util::codecDecoder/Encoderfor any#[bin]message:Framed::new(tcp, BinCodec::<T>::new())(a stream) orUdpFramed::new(udp, …)(a datagramStream + Sinkof(T, addr)) — one codec, both async transports. Impliesbytes. This is bnb’s async support: a native asyncSource/Sinkfamily is deliberately out of scope (the codec is in-memory and fast; framing is the async boundary, andBinCodeccovers it).net— ergonomicstdsocket helpers:MessageStream(whole-message read/write over anyRead + Write, e.g. aTcpStream, notry_clone) andMessageDatagram(send_message/recv_messageover a sealedDatagramSocket—UdpSocketorUnixDatagram). Impliesstd.mock— test-only in-memory transports for exercisingnetcode without a real socket:MockDatagramSocket(aDatagramSocket) andMockStream(aRead + Write, with chunked delivery to drive the read-more path). Put it in your[dev-dependencies]. Impliesnet.
Without std you still get the full macro surface plus: decode from a &[u8]
(BitReader, Type::decode/decode_all/decode_iter/decode_exact/peek), encode to a
Vec<u8> (Type::to_bytes/to_canonical_bytes, or BitEncode::bit_encode over a Sink),
and incremental framing with BitBuf — push bytes from any transport (a UART ISR, a
radio, a channel), pull whole messages; BitBuf::bounded gives an alloc-once fixed
footprint. 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. That is the
deliberate no_std boundary: streaming reader adapters without std are out of scope for 1.0
(if demanded later, they’d arrive as additive adapters over the ecosystem’s embedded-io
traits — see ROADMAP.md).
§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::mapping—#[bin(map/bw_map = …)]: a whole struct mapped to/from a wire type.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.guide::migrating— coming frombinrw/modular-bitfield/num_enum.
Re-exports§
pub use bitstream::BitAmount;pub use bitstream::BitBuf;pub use bitstream::BitDecode;pub use bitstream::BitEncode;pub use bitstream::BitError;pub use bitstream::BitReader;pub use bitstream::BitWriter;pub use bitstream::CapacityError;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::BufSource;stdpub use bitstream::EncodeExt;stdpub use bitstream::SeekReader;stdpub use bitstream::SinkWriter;stdpub use bitstream::SourceReader;stdpub use bitstream::StreamBitReader;stdpub use bitstream::BytesReader;bytespub use bitstream::BytesWriter;bytespub use framing::BinCodec;tokiopub use net::DatagramSocket;netpub use net::MessageDatagram;netpub use net::MessageStream;netpub use net::MockDatagramSocket;mockpub use net::MockStream;mockpub use builder::BuilderError;pub use error::UnknownDiscriminant;pub use error::WidthError;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]. - codecs
- Ready-made field codecs for
parse_with/write_with— LEB128 varints, NUL-terminated C strings, and length-prefixed strings. - error
- The crate’s checked-construction error types.
- framing
tokio - Async framing — a
tokio_util::codecadapter (thetokiofeature). Async framing viatokio_util::codec— thetokiofeature. - guide
- The
bnbguide — worked, runnable walkthroughs. - int
- Arbitrary-width unsigned integers (
u1..u127) — the substrate for sub-byte bitfield fields. Replaces thearbitrary-intdependency. - net
net - Ergonomic
stdsocket helpers —MessageStream+MessageDatagram(thenetfeature). Ergonomicstdsocket helpers — thenetfeature. - prelude
- Common imports for the codec — the typed positioning amounts (
4.bits(),3.bytes()) used by#[br(pad_before = …)]etc., plus theEncodeExttrait that carriesencode(writer)(thestdfeature).
Macros§
- impl_
bits - Implements
Bitsfor a hand-written field type from one pair ofconst fnconversion bodies — the supported way to make a custom type usable as a#[bitfield]field.
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.
- WireLen
- A wire length/count field:
Auto-derived by default, or an explicitSetoverride. See the module docs.
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]).