1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//! Builder composition (ROADMAP Phase 1, chunk C): a codec struct derives
//! `BitsBuilder` alongside `BitDecode`/`BitEncode` — required-by-default
//! construction that round-trips through the codec. (Folding the builder into one
//! `#[bin]` macro is Phase 2; for now it composes as a separate derive.)
mod macro_ {
use bnb::{BitDecode, BitEncode, BitsBuilder, BuilderError, u4, u12};
#[derive(BitDecode, BitEncode, BitsBuilder, Debug, PartialEq, Eq, Clone, Copy)]
struct Header {
version: u4,
#[builder(default)] // optional -> 0 if unset
flags: u4,
payload_len: u12, // 4 + 4 + 12 = 20 bits
}
#[test]
fn builds_with_defaults_and_round_trips() {
let h = Header::builder()
.version(u4::new(4))
.payload_len(u12::new(100))
// flags omitted -> #[builder(default)] -> 0
.build()
.unwrap();
assert_eq!(
h,
Header {
version: u4::new(4),
flags: u4::new(0),
payload_len: u12::new(100),
}
);
// The built value round-trips through the codec.
let bytes = h.to_bytes().unwrap();
assert_eq!(Header::decode_exact(&bytes).unwrap(), h);
}
#[test]
fn required_fields_are_enforced() {
// version + payload_len are required (no `#[builder(default)]`).
let err = Header::builder().version(u4::new(4)).build().unwrap_err();
assert_eq!(err, BuilderError::MissingField("payload_len"));
}
}