Skip to main content

bin

Attribute Macro bin 

Source
#[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 newtypecodec = <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.