bnb/guide/builders.rs
1//! `#[derive(BitsBuilder)]` — a required-by-default builder.
2//!
3//! The infix `with_*` setters are infallible and start from an all-zero value, so a
4//! field you forget is silently zero. The builder closes that gap: every field is
5//! **required** unless opted out, and `build()` returns an error naming the first
6//! unset one.
7//!
8//! ```
9//! use bnb::{bitfield, u4, BitsBuilder};
10//!
11//! #[bitfield(u16, bits = msb)]
12//! #[derive(BitsBuilder, Clone, Copy)]
13//! struct State {
14//! opcode: u4,
15//! flags: u8,
16//! rcode: u4,
17//! }
18//!
19//! let s = State::builder()
20//! .opcode(u4::new(2))
21//! .flags(0)
22//! .rcode(u4::new(3))
23//! .build()
24//! .unwrap();
25//! assert_eq!(s.opcode().value(), 2);
26//! ```
27//!
28//! Forget a required field and `build()` tells you which — at run time, by name:
29//!
30//! ```
31//! # use bnb::{bitfield, u4, BitsBuilder, BuilderError};
32//! # #[bitfield(u16, bits = msb)] #[derive(BitsBuilder, Clone, Copy, Debug)]
33//! # struct State { opcode: u4, flags: u8, rcode: u4 }
34//! let err = State::builder().opcode(u4::new(2)).rcode(u4::new(3)).build().unwrap_err();
35//! assert_eq!(err, BuilderError::MissingField("flags"));
36//! assert_eq!(err.field(), Some("flags"));
37//! ```
38//!
39//! # Opting a field out: `#[builder(default)]`
40//!
41//! Mark a field optional with `#[builder(default)]` (uses `Default::default()` if
42//! unset) or `#[builder(default = expr)]` (uses `expr`):
43//!
44//! ```
45//! use bnb::{bitfield, u4, BitsBuilder};
46//!
47//! #[bitfield(u16, bits = msb)]
48//! #[derive(BitsBuilder, Clone, Copy)]
49//! struct State {
50//! opcode: u4,
51//! #[builder(default)] // 0 if unset
52//! flags: u8,
53//! #[builder(default = u4::new(1))] // a custom default if unset
54//! rcode: u4,
55//! }
56//!
57//! let s = State::builder().opcode(u4::new(2)).build().unwrap(); // flags + rcode defaulted
58//! assert_eq!(s.flags(), 0);
59//! assert_eq!(s.rcode().value(), 1);
60//! ```
61//!
62//! # On plain structs and the `#[bitfield]` intercept
63//!
64//! `#[derive(BitsBuilder)]` also works on a plain struct, and `#[bin]` generates the
65//! same builder automatically (you don't write the derive there). On a `#[bitfield]`,
66//! the attribute collapses the struct to one integer *before* a normal derive could
67//! see the fields, so `#[bitfield]` itself intercepts the `BitsBuilder` marker — which
68//! is why it must sit **above** the `#[derive(...)]`:
69//!
70//! ```
71//! use bnb::{bitfield, u4, BitsBuilder};
72//! #[bitfield(u8, bits = msb)] // must be above the derive
73//! #[derive(BitsBuilder, Clone, Copy)]
74//! struct Nibble { hi: u4, lo: u4 }
75//! assert_eq!(Nibble::builder().hi(u4::new(0xA)).lo(u4::new(0xB)).build().unwrap().hi().value(), 0xA);
76//! ```
77//!
78//! In a `#[bin]` message the builder is generated for you and is where the
79//! [`validate`](super::directives) soundness hook runs — see
80//! [`bin_codec`](super::bin_codec).