#[bin]Expand description
#[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 of bnb::Bits fields, read and
written at arbitrary bit offsets.
#[bin(big, validate = Frame::check)]
#[derive(Debug, PartialEq)]
struct Frame {
version: u4,
#[builder(default)] flags: u4,
#[br(temp)] #[bw(calc = self.payload.len() as u16)] len: u16,
#[br(count = len)] payload: Vec<u8>,
}
// -> Frame::{decode, decode_all, decode_iter, peek, decode_exact},
// Frame::{to_bytes, encode}, Frame::new(..), and Frame::builder()§Struct-level options
big / little or bytes = big|little (byte order), bits = msb|lsb, magic = <expr> (a leading
constant verified on read / emitted on write), read_only / write_only
(directional), no_builder, forward_only (bound decoding to a forward Source),
ctx(name: Ty, …) (context from the parent), validate = <path> (a soundness
check run by build() — the parser stays permissive),
map/try_map/wire/try_wire (map the whole struct to/from a wire type — see
bnb::guide::mapping), auto_len(<field>.<nested> = count|bytes(<source>), …)
(cross-struct WireLen derivation), and — on a single-field
tuple newtype — codec = <module> / codec(parse = <f>, write = <f>) (the
per-type field codec: the type’s wire form is owned by the fn pair; use it as a
plain field anywhere, with #[brw(variable)] in a fixed parent).
bits = msb and bytes = big are the defaults, and big+msb is the natural
pairing (network byte order); the declared byte order only swaps a byte-multiple
value that differs from the bit order’s natural layout, never a sub-byte field. See
bnb::guide::bin_codec § “Byte order × bit order” for the rule.
§Field directives
#[br]/#[bw]: count, ctx { … }, temp + calc, if(…),
assert(<expr>[, "fmt", args…]) (a decode-time guard over this and earlier fields —
the explicit opt-in strictness escape hatch; read-only, no inverse), map/try_map
(+ the inverse bw(map)), parse_with/write_with, pad_before/after,
align_before/after, seek = <bits>, restore_position, dbg (trace a field as it
decodes), #[bw(auto_len = count(<field>)|bytes(<field>))] (derive a WireLen<T>
field from a sibling target — the primary WireLen workflow); #[brw(ignore)]
(neither read nor written); #[brw(variable)] (the
field’s type is a variable-length custom codec — suppresses the parent’s
FixedBitLen); #[brw(count_prefix = <Ty>)]
on a Vec<_> (the length-prefixed count sugar — generates the temp+calc+count
triad: the prefix sizes the Vec on read and is recomputed, checked, from
len() on write; any Bits prefix type incl. uN); #[try_str] (render a
byte-buffer field as text in Debug); plus #[reserved] / #[reserved_with(…)].
§On an enum — tagged-union dispatch
#[bin] also applies to an enum, dispatching on two orthogonal concepts: a
magic wire constant (a byte string or width-suffixed unsigned int, read and
written — the discriminant, or a verified signature on a tag-variant) and a tag
selector taken from ctx (read-only, never on the wire). With per-variant magics
the enum reads the discriminant and matches (a single == for uniform widths, or a
peek-and-starts_with for variable-width byte strings). With #[bin(tag = <ctx-param>)]
and variant #[bin(tag = V)] it dispatches on the selector and writes no discriminant;
the two compose (and may even be mixed in one enum — tag priority, then magic). The
“nothing matched” tail is a #[catch_all] (preserving the unknown discriminant) or a
typed no-tag/no-magic fallback variant, not both; without either a magic enum is a
closed set. An optional enum-level magic is a leading prefix. Variants may be unit,
tuple, named, or #[nested]. The codec also generates decode_as_<variant>,
peek_variant/<Name>Kind, decode_tagged, and a magic()/tag() accessor where
the discriminant is single-valued. See the bnb::guide::dispatch page.
On a struct, #[bin] lowers to #[derive(BitDecode, BitEncode, BitsBuilder)], which
stay usable directly. See the bnb::guide::bin_codec page for a full walkthrough and
bnb::guide::directives for one runnable example per directive.