bnb/guide/bitfields.rs
1//! `#[bitfield]` — pack typed fields into one backing integer.
2//!
3//! A `#[bitfield]` collapses a struct of `Bits`-typed fields into a single unsigned
4//! integer, generating accessors that shift and mask. It is the tool for a run of
5//! sub-byte fields that together fill one word (a flags/opcode byte, a VLAN tag, an
6//! IPv4 first byte).
7//!
8//! ```
9//! use bnb::{bitfield, u4};
10//!
11//! #[bitfield(u8, bits = msb)]
12//! #[derive(Clone, Copy)]
13//! struct VersionIhl {
14//! version: u4, // high nibble
15//! ihl: u4, // low nibble
16//! }
17//!
18//! let b = VersionIhl::new().with_version(u4::new(4)).with_ihl(u4::new(5));
19//! assert_eq!(b.raw(), 0x45); // the classic IPv4 first byte
20//! assert_eq!(b.version().value(), 4);
21//! ```
22//!
23//! # Generated API
24//!
25//! For a field `f: T`, you get `f() -> T`, `with_f(T) -> Self` (consuming, chainable),
26//! and `set_f(&mut self, T)`. Plus `new()` (all-zero), `raw()`/`from_raw()`, and
27//! allocation-free byte conversions: `to_bytes`/`from_bytes` serialize in the **declared**
28//! byte order (`bytes = be|le`), while `to_be_bytes`/`to_le_bytes`/`from_be_bytes`/`from_le_bytes`
29//! force a specific endianness (the override). The type also implements [`Bits`](crate::Bits)
30//! and [`Bitfield`](crate::Bitfield), so it nests in another bitfield or a `#[bin]` message.
31//!
32//! ```
33//! use bnb::{bitfield, u4};
34//! # #[bitfield(u8, bits = msb)] #[derive(Clone, Copy)] struct VersionIhl { version: u4, ihl: u4 }
35//! let mut b = VersionIhl::new().with_version(u4::new(4)).with_ihl(u4::new(5));
36//! b.set_ihl(u4::new(6));
37//! assert_eq!(b.ihl().value(), 6);
38//! assert_eq!(VersionIhl::from_be_bytes([0x45]).version().value(), 4);
39//! ```
40//!
41//! # Bit order vs. byte order — two independent knobs
42//!
43//! - `bits = msb | lsb` (default `msb`): does the **first** declared field land in the
44//! high or low bits of the backing integer. `msb` matches the ASCII-art layouts in
45//! RFCs (first field drawn leftmost = most significant).
46//! - `bytes = be | le` (default `be`): the byte order `to_bytes`/`from_bytes` use when
47//! serializing the backing integer.
48//!
49//! They are orthogonal. The same fields, packed `msb`, declared with two different byte
50//! orders — `to_bytes` honors each declaration:
51//!
52//! ```
53//! use bnb::{bitfield, u4};
54//!
55//! #[bitfield(u16, bits = msb, bytes = be)]
56//! #[derive(Clone, Copy)]
57//! struct Be { hi: u4, mid: u8, lo: u4 }
58//!
59//! #[bitfield(u16, bits = msb, bytes = le)]
60//! #[derive(Clone, Copy)]
61//! struct Le { hi: u4, mid: u8, lo: u4 }
62//!
63//! let be = Be::new().with_hi(u4::new(0xA)).with_mid(0xBC).with_lo(u4::new(0xD));
64//! let le = Le::new().with_hi(u4::new(0xA)).with_mid(0xBC).with_lo(u4::new(0xD));
65//! assert_eq!(be.to_bytes(), [0xAB, 0xCD]); // declared `be` -> big-endian bytes
66//! assert_eq!(le.to_bytes(), [0xCD, 0xAB]); // same logical value, declared `le`
67//!
68//! // `to_be_bytes`/`to_le_bytes` ignore the declaration — use them only to override it.
69//! assert_eq!(le.to_be_bytes(), [0xAB, 0xCD]);
70//! ```
71//!
72//! # Field widths: inferred, explicit, or ranged
73//!
74//! In order of precedence:
75//!
76//! 1. **Inferred** (no attribute): the field's width is `<T as Bits>::BITS`. Fields
77//! pack adjacently in declaration order. This is the common case.
78//! 2. **`#[bits(N)]`**: an explicit width, still auto-placed. Useful when a field's
79//! type is wider than the bits it should occupy.
80//! 3. **`#[bits(A..=B)]`**: an absolute, inclusive bit range — fully manual layout,
81//! the equivalent of `bitbybit`'s `bits = A..=B`. Use ranges on **every** field, or
82//! on none; the two styles can't be mixed in one struct.
83//!
84//! With inferred widths the declared total is the sum of the fields (gaps are not
85//! transmitted); with ranges the width is the whole backing integer (gaps are real
86//! reserved bits on the wire).
87//!
88//! ```
89//! use bnb::bitfield;
90//!
91//! // Manual layout: two fields with a deliberate 3-bit gap inside a u32.
92//! #[bitfield(u32, bits = msb)]
93//! #[derive(Clone, Copy)]
94//! struct Manual {
95//! #[bits(20..=31)] tag: bnb::u12, // top 12 bits
96//! #[bits(0..=16)] body: bnb::u17, // low 17 bits; bits 17..=19 are reserved
97//! }
98//!
99//! let m = Manual::new().with_tag(bnb::u12::new(0xABC)).with_body(bnb::u17::new(1));
100//! assert_eq!(m.tag().value(), 0xABC);
101//! assert_eq!(m.body().value(), 1);
102//! ```
103//!
104//! A reversed range (`#[bits(31..=20)]`) is a clear compile error, not a silent
105//! overflow, and field widths that exceed the backing integer fail a const assert.
106//!
107//! # Nesting
108//!
109//! Because a `#[bitfield]` is itself a `Bits` value, bitfields nest. A 5-bit field of
110//! a nested type contributes exactly 5 bits to its parent:
111//!
112//! ```
113//! use bnb::{bitfield, BitEnum, u3, u5};
114//!
115//! #[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
116//! #[bit_enum(u3)]
117//! enum Op { Read, Write, #[catch_all] Other(u3) }
118//!
119//! #[bitfield(u8, bits = msb)]
120//! #[derive(Clone, Copy)]
121//! struct Cmd { op: Op, addr: u5 } // 3 + 5 = 8 bits exactly
122//!
123//! let c = Cmd::new().with_op(Op::Write).with_addr(u5::new(0x11));
124//! assert_eq!(c.op(), Op::Write);
125//! assert_eq!(c.addr().value(), 0x11);
126//! ```
127//!
128//! See [`enums`](super::enums) and [`flags`](super::flags) for the field types that
129//! nest here, and [`composition`](super::composition) for the full picture.