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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//! `#[reserved]` / `#[reserved_with]`: a reserved field is a normal **stored** field
//! with a known *spec value* (the type's zero, or the `reserved_with` expression). On
//! the verbatim path (`decode`/`to_bytes`) it reads/writes its actual value — so a peer's
//! reserved bits are observable and overridable (dual-use). The builder defaults it to the
//! spec value (so it isn't required), and the **canonical** encoder (`to_canonical_bytes`)
//! writes the spec value instead.
mod macro_ {
use bnb::{bin, u3, u4};
#[bin]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame {
version: u4,
#[reserved]
rsv: u4,
payload: u8,
}
#[test]
fn builder_defaults_reserved_to_spec_but_allows_override() {
// Optional in the builder: omitting it defaults to the spec value (0).
let f = Frame::builder()
.version(u4::new(5))
.payload(0xAB)
.build()
.unwrap();
assert_eq!(f.rsv, u4::new(0));
assert_eq!(f.to_bytes().unwrap(), [0x50, 0xAB]); // version(0101) reserved(0000)
// ...but you can override it to emit non-spec reserved bits.
let g = Frame::builder()
.version(u4::new(5))
.rsv(u4::new(0xF))
.payload(0xAB)
.build()
.unwrap();
assert_eq!(g.to_bytes().unwrap(), [0x5F, 0xAB]); // verbatim: the actual value on the wire
assert_eq!(g.to_canonical_bytes().unwrap(), [0x50, 0xAB]); // canonical: the spec value
}
#[test]
fn decode_is_verbatim_canonical_encode_normalizes() {
// The decoder is always verbatim — it captures the actual reserved bits from the wire.
let actual = Frame::decode_exact(&[0x5F, 0xAB]).unwrap();
assert_eq!(actual.rsv, u4::new(0xF));
assert_eq!(actual.version, u4::new(5));
assert_eq!(actual.payload, 0xAB);
// `to_bytes` re-emits those bits exactly (a faithful round-trip)...
assert_eq!(actual.to_bytes().unwrap(), [0x5F, 0xAB]);
// ...while `to_canonical_bytes` forces the reserved field to its spec value (0).
assert_eq!(actual.to_canonical_bytes().unwrap(), [0x50, 0xAB]);
}
#[bin]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame2 {
tag: u4,
#[reserved_with(u3::new(0b111))]
must_be_one: u3,
rest: u4,
}
#[test]
fn reserved_with_spec_value_is_the_pattern() {
// The builder defaults the reserved field to the must-be-one pattern.
let f = Frame2::builder()
.tag(u4::new(0xA))
.rest(u4::new(0x5))
.build()
.unwrap();
assert_eq!(f.must_be_one, u3::new(0b111));
assert_eq!(f.to_bytes().unwrap()[0], 0xAE); // tag(1010) reserved(111) rest-high(0)
// Override to a non-spec value: `to_bytes` puts it on the wire verbatim, while
// `to_canonical_bytes` forces the pattern back. (The builder lets a caller set the
// reserved field to a non-spec value on purpose — dual-use.)
let g = Frame2::builder()
.tag(u4::new(0xA))
.must_be_one(u3::new(0))
.rest(u4::new(0x5))
.build()
.unwrap();
assert_eq!(g.to_bytes().unwrap()[0], 0xA0); // verbatim: reserved(000)
assert_eq!(g.to_canonical_bytes().unwrap()[0], 0xAE); // canonical: reserved forced to 111
// Decode is verbatim: it reads back exactly the non-spec bits we wrote.
assert_eq!(
Frame2::decode_exact(&g.to_bytes().unwrap())
.unwrap()
.must_be_one,
u3::new(0)
);
}
}