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
//! **reserved** — `#[reserved]` fields + the **verbatim vs canonical** encode model. A reserved
//! field is a normal *stored* field with a known spec value: the decoder captures the actual
//! wire bits (dual-use — observable and overridable), `to_bytes` re-emits them **verbatim**, and
//! `to_canonical_bytes` **normalizes** them to spec. The in-memory helpers (`is_canonical`,
//! `canonical_diff`, `to_canonical`) round it out.
//!
//! Run with: `cargo run -p bitsandbytes --example reserved`
use bnb::prelude::*; // brings `EncodeExt::encode(writer)` into scope
use bnb::{bin, u4};
#[bin(big)]
#[derive(Debug, PartialEq, Eq, Clone)]
struct Frame {
version: u4,
#[reserved]
rsv: u4, // spec value is 0
payload: u16,
}
fn main() {
// A peer left non-spec bits in the reserved nibble; the decoder captures them verbatim.
let received = Frame::decode_exact(&[0x5F, 0x12, 0x34]).unwrap();
println!("{received:#?}");
assert_eq!(received.rsv, u4::new(0xF));
// Verbatim re-emits exactly what's held...
assert_eq!(received.to_bytes().unwrap(), [0x5F, 0x12, 0x34]);
// ...canonical forces the reserved field back to its spec value.
assert_eq!(received.to_canonical_bytes().unwrap(), [0x50, 0x12, 0x34]);
// In-memory helpers: is it canonical, and which fields differ?
println!("is_canonical = {}", received.is_canonical());
println!("canonical_diff = {:?}", received.canonical_diff());
assert!(!received.is_canonical());
assert_eq!(received.canonical_diff(), vec!["rsv"]);
// Get a fresh, normalized value directly...
let canon = received.to_canonical();
assert!(canon.is_canonical());
assert!(canon.canonical_diff().is_empty());
// ...and encode it: the std `encode(writer)` is verbatim, so encoding the canonical copy
// emits the normalized bytes.
let mut out = Vec::new();
canon.encode(&mut out).unwrap();
println!("to_canonical().encode() -> {out:02x?}");
assert_eq!(out, [0x50, 0x12, 0x34]);
// Built from scratch: the reserved field defaults to spec, so it's optional and canonical.
let built = Frame::builder()
.version(u4::new(3))
.payload(0xBEEF)
.build()
.unwrap();
assert!(built.is_canonical());
println!("built: {built:#?}");
println!("all checks passed");
}