Skip to main content

bnb/guide/
bin_codec.rs

1//! `#[bin]` — the unified whole-message codec.
2//!
3//! `#[bin]` folds three things over one struct: the read codec, the write codec, and a
4//! required-by-default builder. Fields are read and written at arbitrary **bit**
5//! offsets, so the same attribute handles byte-aligned headers and sub-byte frames,
6//! and any [`Bits`](crate::Bits) type — including a `#[bitfield]`, `#[derive(BitEnum)]`,
7//! or `#[bitflags]` — drops in as one field with no glue.
8//!
9//! # A DNS header, end to end
10//!
11//! The 12-byte DNS message header (RFC 1035 §4.1.1) is a good tour: a 16-bit flags
12//! word (itself a bitfield of enums and bools) between five `u16` counts/ids.
13//!
14//! ```
15//! use bnb::{bin, bitfield, BitEnum, u3, u4};
16//!
17//! #[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
18//! #[bit_enum(u4)]
19//! enum OpCode { Query, IQuery, Status, #[catch_all] Other(u4) }
20//!
21//! #[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
22//! #[bit_enum(u4)]
23//! enum RCode { NoError, FormErr, ServFail, NxDomain, #[catch_all] Other(u4) }
24//!
25//! // The 16-bit flags word, MSB-first (RFC diagram order), big-endian.
26//! #[bitfield(u16, bits = msb, bytes = big)]
27//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
28//! struct Flags {
29//!     qr: bool, opcode: OpCode, aa: bool, tc: bool,
30//!     rd: bool, ra: bool, z: u3, rcode: RCode,   // 1+4+1+1+1+1+3+4 = 16
31//! }
32//!
33//! #[bin(big)]
34//! #[derive(Debug, Clone, PartialEq)]
35//! struct Header {
36//!     id: u16,
37//!     flags: Flags,        // a 16-bit bitfield, nested as one field
38//!     qdcount: u16,
39//!     ancount: u16,
40//!     nscount: u16,
41//!     arcount: u16,
42//! }
43//!
44//! // Build with the required-by-default builder.
45//! let flags = Flags::new().with_qr(true).with_rd(true).with_ra(true);
46//! let h = Header::builder()
47//!     .id(0x1234).flags(flags)
48//!     .qdcount(1).ancount(1).nscount(0).arcount(0)
49//!     .build().unwrap();
50//!
51//! // Encode -> 12 bytes; decode is the exact inverse.
52//! let bytes = h.to_bytes().unwrap();
53//! assert_eq!(bytes.len(), 12);
54//! assert_eq!(&bytes[..4], &[0x12, 0x34, 0x81, 0x80]); // id, then flags 0x8180
55//! assert_eq!(Header::decode_exact(&bytes).unwrap(), h);
56//! ```
57//!
58//! # The generated API
59//!
60//! Every `#[bin]` type gets a consistent surface:
61//!
62//! | Direction | Method | Use |
63//! |---|---|---|
64//! | decode | `decode(&mut S)` | one message from a [`Source`](crate::Source) cursor (`BitReader`/socket/file/[`BitBuf`](crate::BitBuf)), advancing it |
65//! | decode | `decode_exact(&[u8])` | one message that consumes every whole byte |
66//! | decode | `decode_all(&[u8]) -> Vec<_>` | every message in the buffer (bit-aware, layout baked in) |
67//! | decode | `decode_iter(&[u8])` | a lazy iterator over the buffer's messages |
68//! | decode | `peek(&[u8])` | one message, tail-tolerant, no buffer mutation |
69//! | encode | `to_bytes() -> Vec<u8>` | encode to a fresh buffer (**verbatim**) |
70//! | encode | `to_canonical_bytes()` | encode the spec-normalized form (**canonical**) † |
71//! | encode | `encode(&mut W)` | encode to any [`std::io::Write`] (**verbatim**) |
72//! | encode | `bit_encode(&mut K)` | write into an explicit [`Sink`](crate::Sink) — a [`BitEncode`](crate::BitEncode) trait method (`canonical_bit_encode` for the canonical form) |
73//! | build | `builder()` | the required-by-default builder |
74//! | build | `Name { … }` | a struct literal names every stored field directly |
75//!
76//! `decode_exact`/`decode_all`/`peek`/`to_bytes` are the everyday slice/`Vec` path;
77//! `decode`/`encode(&mut W)`/`bit_encode` open the door to the
78//! [I/O ladder](super::io). († `to_canonical_bytes` and the canonical helpers exist only when
79//! the message has a `reserved` or `calc` field — see
80//! [Two encode forms](#two-encode-forms-verbatim-vs-canonical).)
81//!
82//! ## Decoding a buffer of messages
83//!
84//! `decode_all` / `decode_iter` walk a `&[u8]` of back-to-back messages — bit-aware (a message
85//! needn't end on a byte boundary) and decoding in the message's own byte/bit order:
86//!
87//! ```
88//! use bnb::bin;
89//! #[bin(big)]
90//! #[derive(Debug, PartialEq, Eq)]
91//! struct Ping { seq: u16 }
92//!
93//! let wire = [0x00, 0x01, 0x00, 0x02, 0x00, 0x03]; // three Pings, back to back
94//! assert_eq!(Ping::decode_all(&wire).unwrap(),
95//!            vec![Ping { seq: 1 }, Ping { seq: 2 }, Ping { seq: 3 }]);
96//! // decode_iter is the lazy form (yields Result per message):
97//! assert_eq!(Ping::decode_iter(&wire).filter_map(Result::ok).count(), 3);
98//! ```
99//!
100//! For a *cursor* — a stream, socket, or [`BitBuf`](crate::BitBuf) — reach for `decode(&mut S)`
101//! instead (see the [I/O ladder](super::io)).
102//!
103//! # Struct-level options
104//!
105//! Inside `#[bin(...)]`:
106//!
107//! - `big` / `little` — byte order (default `big`).
108//! - `bits = msb | lsb` — bit order (default `msb`).
109//! - `magic = <expr>` — a leading constant verified on read, emitted on write.
110//! - `read_only` / `write_only` — generate only one direction.
111//! - `no_builder` — skip the builder.
112//! - `forward_only` — bound decoding to a forward `Source` (a seek directive is then a
113//!   compile error).
114//! - `ctx(name: Ty, …)` — declare context the message needs from its parent.
115//! - `validate = <path>` — a soundness check run by `build()`.
116//!
117//! ## Each option, by example
118//!
119//! Byte and bit order:
120//!
121//! ```
122//! use bnb::{bin, u4};
123//!
124//! #[bin(little)] // little-endian byte order
125//! #[derive(Debug, PartialEq)]
126//! struct Le { v: u32 }
127//! assert_eq!(Le { v: 0x1234_5678 }.to_bytes().unwrap(), [0x78, 0x56, 0x34, 0x12]);
128//!
129//! #[bin(big, bits = lsb)] // the first field lands in the LOW bits of the byte
130//! #[derive(Debug, PartialEq)]
131//! struct Lsb { a: u4, b: u4 }
132//! assert_eq!(Lsb { a: u4::new(0xA), b: u4::new(0xB) }.to_bytes().unwrap(), [0xBA]);
133//! ```
134//!
135//! ### Byte order × bit order — the natural-layout rule
136//!
137//! The two knobs aren't fully independent — they compose by one rule. Each bit order has
138//! a *natural* byte layout: MSB-first emits a value's high bits first, so its bytes land
139//! **big-endian**; LSB-first emits low bits first, so they land **little-endian** (value
140//! bit *k* → stream bit *k* — exactly the CAN/DBC "Intel" layout, `raw |= v << start;
141//! raw.to_le_bytes()`). The declared byte order swaps a **byte-multiple** value only when
142//! it *differs* from that natural layout; sub-byte widths are never byte-swapped. So the
143//! two identity corners are the real-world conventions — `big`+`msb` is network order,
144//! `little`+`lsb` is DBC-Intel/SMB — and the mixed corners (`little`+`msb`, `big`+`lsb`)
145//! are the deliberate byte swaps.
146//!
147//! ```
148//! use bnb::bin;
149//!
150//! // `little`+`lsb` is an identity corner: a byte-multiple value needs no swap, so it
151//! // lands in `to_le_bytes` order — the DBC-Intel convention.
152//! #[bin(little, bits = lsb)]
153//! #[derive(Debug, PartialEq)]
154//! struct Intel { v: u32 }
155//! assert_eq!(Intel { v: 0x1234_5678 }.to_bytes().unwrap(), 0x1234_5678u32.to_le_bytes());
156//! assert_eq!(Intel { v: 0x1234_5678 }.to_bytes().unwrap(), [0x78, 0x56, 0x34, 0x12]);
157//!
158//! // The `big`+`msb` identity corner is the mirror image: network byte order.
159//! #[bin(big, bits = msb)]
160//! #[derive(Debug, PartialEq)]
161//! struct Net { v: u32 }
162//! assert_eq!(Net { v: 0x1234_5678 }.to_bytes().unwrap(), [0x12, 0x34, 0x56, 0x78]);
163//! ```
164//!
165//! Directional codecs and the builder:
166//!
167//! ```
168//! use bnb::bin;
169//!
170//! #[bin(big, read_only)] // only decodes — no `to_bytes`/`encode`
171//! #[derive(Debug, PartialEq)]
172//! struct Ro { v: u16 }
173//! assert_eq!(Ro::decode_exact(&[0x12, 0x34]).unwrap(), Ro { v: 0x1234 });
174//!
175//! #[bin(big, write_only)] // only encodes — no `decode`/`peek`
176//! struct Wo { v: u16 }
177//! assert_eq!(Wo { v: 0x1234 }.to_bytes().unwrap(), [0x12, 0x34]);
178//!
179//! #[bin(big, no_builder)] // no `Nb::builder()` — construct directly
180//! #[derive(Debug, PartialEq)]
181//! struct Nb { v: u16 }
182//! assert_eq!(Nb { v: 5 }.to_bytes().unwrap(), [0x00, 0x05]);
183//! ```
184//!
185//! `forward_only` — decode from a non-seekable stream, with a compile-time no-seek
186//! guarantee (a `#[br(restore_position)]` field would then be a compile error):
187//!
188//! ```
189//! use bnb::{bin, StreamBitReader};
190//!
191//! #[bin(big, forward_only)]
192//! #[derive(Debug, PartialEq)]
193//! struct Hdr { magic: u16, len: u16 }
194//!
195//! let data: &[u8] = &[0xCA, 0xFE, 0x00, 0x10]; // `&[u8]` is `Read` but not `Seek`
196//! let mut s = StreamBitReader::new(data);
197//! assert_eq!(Hdr::decode(&mut s).unwrap(), Hdr { magic: 0xCAFE, len: 16 });
198//! ```
199//!
200//! `ctx(...)` — context a message needs from its parent **to decode**. The parent passes it
201//! with `#[br(ctx { … })]`; standalone, `decode_with`/`decode_with_exact` take a `…Ctx`
202//! (built positionally with `…Ctx::new`). `ctx` is **decode-only**: encode stays a plain
203//! `to_bytes()` unless the *write* side actually reads a ctx param (a keyed `bw(map)`,
204//! `calc`, or `write_with`), in which case the type gets `to_bytes_with`/`encode_with`:
205//!
206//! ```
207//! use bnb::bin;
208//!
209//! #[bin(big, ctx(len: u16))]
210//! #[derive(Debug, PartialEq)]
211//! struct Body {
212//!     #[br(count = len)]
213//!     data: Vec<u8>,
214//! }
215//!
216//! #[bin(big)]
217//! #[derive(Debug, PartialEq)]
218//! struct Packet {
219//!     len: u16,
220//!     #[br(ctx { len })] // pass `len` to `Body`
221//!     body: Body,
222//! }
223//!
224//! let p = Packet { len: 3, body: Body { data: vec![1, 2, 3] } };
225//! assert_eq!(p.to_bytes().unwrap(), [0x00, 0x03, 1, 2, 3]);
226//! assert_eq!(Packet::decode_exact(&[0x00, 0x03, 1, 2, 3]).unwrap(), p);
227//!
228//! // Standalone: decode needs the context (build it with `BodyCtx::new`); encode is
229//! // plain — `ctx` is decode-only, and `Body`'s write side doesn't read `len`.
230//! let b = Body::decode_with_exact(&[0xAA, 0xBB], BodyCtx::new(2)).unwrap();
231//! assert_eq!(b.data, vec![0xAA, 0xBB]);
232//! assert_eq!(b.to_bytes().unwrap(), vec![0xAA, 0xBB]);
233//! ```
234//!
235//! (`magic` and `validate` are shown below.)
236//!
237//! # Dual-use: `validate` gates the builder, not the parser
238//!
239//! `validate = path` runs a `fn(&Self) -> Result<(), impl Display>` in `build()` only.
240//! The **parser stays permissive** — it never rejects representable input — so a
241//! deliberately malformed message is still decodable (for fuzzing / interop), even
242//! though it can't be *built*. It's also exposed as re-runnable methods: `build()` checks
243//! once, but a value can be mutated before you send it, so **`validate()` / `is_valid()`
244//! re-check the *current* value on demand** (computed, never a stale flag). By convention
245//! `validate` expresses **semantic** soundness — not `calc`/`reserved` fields, which are
246//! representational (normalized by `to_canonical_bytes`), so it's a property of the message's
247//! meaning that holds for the canonical form too.
248//!
249//! ```
250//! use bnb::bin;
251//!
252//! #[bin(big, validate = check)]
253//! #[derive(Debug, PartialEq)]
254//! struct Msg { kind: u8, len: u8 }
255//!
256//! fn check(m: &Msg) -> Result<(), String> {
257//!     if m.kind == 0 { return Err("kind 0 is reserved".into()); }
258//!     Ok(())
259//! }
260//!
261//! assert!(Msg::builder().kind(0).len(4).build().is_err());      // builder: rejected
262//! assert!(Msg::decode_exact(&[0x00, 0x04]).is_ok());            // parser: permissive
263//!
264//! let mut m = Msg::builder().kind(1).len(4).build().unwrap();
265//! assert!(m.is_valid());                                        // sound as built
266//! m.kind = 0;                                                   // mutated before sending…
267//! assert!(!m.is_valid());                                       // …re-check catches it
268//! ```
269//!
270//! # Derived, never-drifting fields
271//!
272//! A length or count you don't want to store can be read into a temp local and
273//! recomputed on write, so it can never disagree with the data. Here `len` drives a
274//! `count`-bound `Vec` on read and is recomputed from `payload.len()` on write:
275//!
276//! ```
277//! use bnb::bin;
278//!
279//! #[bin(big, magic = 0xCAFEu16)]
280//! #[derive(Debug, PartialEq)]
281//! struct Frame {
282//!     #[br(temp)]
283//!     #[bw(calc = self.payload.len() as u8)]
284//!     len: u8,
285//!     #[br(count = len)]
286//!     payload: Vec<u8>,
287//! }
288//!
289//! let f = Frame::builder().payload(vec![0xDE, 0xAD, 0xBE, 0xEF]).build().unwrap();
290//! assert_eq!(f.to_bytes().unwrap(), [0xCA, 0xFE, 0x04, 0xDE, 0xAD, 0xBE, 0xEF]);
291//! assert_eq!(Frame::decode_exact(&[0xCA, 0xFE, 0x02, 0x01, 0x02]).unwrap().payload, vec![1, 2]);
292//! ```
293//!
294//! When the count sits *immediately before* its `Vec` (as here), the whole triad
295//! collapses to one directive on the `Vec` — `#[brw(count_prefix = u8)] payload:
296//! Vec<u8>` — same wire bytes, plus a checked (never-truncating) length on encode.
297//! See [`directives`](super::directives) § `count_prefix`.
298//!
299//! ## `temp` + `calc` vs a stored `calc`
300//!
301//! Whether a `calc` field is also `temp` is the choice between *never keep it* and *keep it
302//! but be able to recompute it*:
303//!
304//! - **`temp` + `calc`** (above) — the field is **not stored**: it's read into a local, written
305//!   from the expression, and absent from the struct. Use it for purely-derived prefixes you
306//!   never need to read back (a `len`/`count`). It always recomputes, so it creates **no
307//!   verbatim/canonical gap** — there's nothing to drift.
308//! - **`calc` *without* `temp`** — the field **is stored** (you can read the decoded value, e.g.
309//!   an as-received checksum), and `to_bytes` writes it **verbatim** while `to_canonical_bytes`
310//!   **recomputes** it. Use it when you want to *inspect or preserve* the on-wire value (dual-use:
311//!   send a deliberately-wrong checksum) yet still be able to emit the correct one. This is what
312//!   makes a message [canonical-bearing](#two-encode-forms-verbatim-vs-canonical).
313//!
314//! # Two encode forms: verbatim vs canonical
315//!
316//! A dual-use codec needs to do two opposite things: reproduce a message **exactly** (even a
317//! malformed one you parsed off the wire), and emit a **spec-clean** one. So `#[bin]` gives
318//! you both, and *never silently* picks for you:
319//!
320//! - **`to_bytes()` is verbatim** — it writes exactly what's stored. Retained `reserved` bits
321//!   stay, a stored `calc` value is written as-is. This is the faithful inverse of `decode`:
322//!   `decode` then `to_bytes` is byte-for-byte identical.
323//! - **`to_canonical_bytes()` is canonical** — `reserved` fields are written as their spec
324//!   value and `calc` fields are recomputed, so the result is always spec-compliant.
325//!
326//! The two differ only when a message has a `reserved` or non-`temp` `calc` field — so
327//! `to_canonical_bytes` (and the three helpers below) are generated **only then**; otherwise
328//! verbatim *is* canonical and only `to_bytes` exists. (`temp` + `calc` fields are never
329//! stored, so they always recompute — they don't create a verbatim/canonical gap.)
330//!
331//! Three helpers inspect or normalize the value **in memory**, without encoding:
332//! `is_canonical()`, `canonical_diff()` (the names of the fields that differ from canonical),
333//! and `to_canonical(self) -> Self`.
334//!
335//! ## Choosing a form
336//!
337//! Every encoder is **explicit** — nothing silently rewrites your data. `to_bytes` /
338//! `bit_encode` / the std-writer [`encode`](crate::EncodeExt::encode) are always **verbatim**;
339//! `to_canonical_bytes` / `canonical_bit_encode` are always **canonical**. To stream the
340//! canonical form over a `std::io::Write`, encode the canonical copy:
341//! `value.to_canonical().encode(&mut w)`. A `reserved`/`calc` field is an ordinary stored field,
342//! so these messages construct via a struct literal, the builder, or `decode`, and coexist with
343//! serde derives fine — one type can carry both codecs (see `tests/serde_compat.rs`; bnb is
344//! deliberately *not* a serde data format, whose model has no bit widths or byte order).
345//!
346//! ```
347//! use bnb::{bin, EncodeExt};
348//!
349//! #[bin(big)]
350//! #[derive(Debug, Clone, PartialEq)]
351//! struct Packet {
352//!     tag: u8,
353//!     #[reserved]
354//!     rsv: u8,                       // spec value 0
355//!     #[bw(calc = self.tag ^ 0x5A)]
356//!     #[builder(default)]
357//!     check: u8,                     // canonical value: tag ^ 0x5A
358//! }
359//!
360//! // A value a peer sent us with non-spec reserved bits and a stale checksum:
361//! let p = Packet::builder().tag(0x10).rsv(0xFF).check(0x99).build().unwrap();
362//!
363//! // VERBATIM — exactly what's stored (so decode -> to_bytes round-trips):
364//! assert_eq!(p.to_bytes().unwrap(), [0x10, 0xFF, 0x99]);
365//!
366//! // CANONICAL — reserved -> 0, checksum recomputed (0x10 ^ 0x5A = 0x4A):
367//! assert_eq!(p.to_canonical_bytes().unwrap(), [0x10, 0x00, 0x4A]);
368//!
369//! // Inspect the gap without encoding:
370//! assert!(!p.is_canonical());
371//! assert_eq!(p.canonical_diff(), ["rsv", "check"]);
372//!
373//! // Stream the canonical form over a writer: encode the canonical copy.
374//! let mut out: Vec<u8> = Vec::new();
375//! p.clone().to_canonical().encode(&mut out).unwrap();
376//! assert_eq!(out, [0x10, 0x00, 0x4A]);
377//! ```
378//!
379//! See [`directives`](super::directives) for every field directive, and
380//! [`io`](super::io) for decoding from a socket or file rather than a slice. The
381//! `examples/bin_message.rs` example in the repository is a runnable version of the
382//! header + frame above.