Skip to main content

bnb/guide/
quick_start.rs

1//! A five-minute tour of every macro.
2//!
3//! Each block below is a complete, runnable example. Together they cover the whole
4//! surface; the later guide pages go deep on each.
5//!
6//! # 1. Arbitrary-width integers
7//!
8//! `u1`..`u127` are range-checked sub-byte integers — the building blocks of packed
9//! fields. The native widths (`u8`/`u16`/…) are the standard library's.
10//!
11//! ```
12//! use bnb::{u4, u12};
13//!
14//! let nibble = u4::new(0xA);          // panics if > 0xF
15//! assert_eq!(nibble.value(), 0xA);
16//! assert!(u4::try_new(0x10).is_err()); // checked construction
17//! assert_eq!(u12::MAX.value(), 0xFFF);
18//! ```
19//!
20//! # 2. `#[bitfield]` — pack typed fields into one integer
21//!
22//! ```
23//! use bnb::{bitfield, u4};
24//!
25//! // A u16 split into three fields, most-significant-first (RFC order).
26//! #[bitfield(u16, bits = msb, bytes = big)]
27//! #[derive(Clone, Copy)]
28//! struct VlanTag {
29//!     pcp: u4,   // high nibble
30//!     dei: bool,
31//!     vid: bnb::u11,
32//! }
33//!
34//! let tag = VlanTag::new().with_pcp(u4::new(5)).with_dei(true).with_vid(bnb::u11::new(100));
35//! assert_eq!(tag.pcp().value(), 5);
36//! assert!(tag.dei());
37//! assert_eq!(tag.vid().value(), 100);
38//! assert_eq!(tag.to_be_bytes().len(), 2);
39//! ```
40//!
41//! # 3. `#[derive(BitEnum)]` — enum ⇄ integer
42//!
43//! A `#[catch_all]` variant preserves unknown values, so a parser never rejects
44//! representable input (the dual-use convention).
45//!
46//! ```
47//! use bnb::{BitEnum, Bits, u4};
48//!
49//! #[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
50//! #[bit_enum(u4)]
51//! enum RCode {
52//!     NoError,
53//!     FormErr,
54//!     ServFail,
55//!     #[catch_all]
56//!     Other(u4),
57//! }
58//!
59//! assert_eq!(RCode::from_bits(2), RCode::ServFail);
60//! assert_eq!(RCode::from_bits(9), RCode::Other(u4::new(9))); // unknown, preserved
61//! assert_eq!(RCode::Other(u4::new(9)).into_bits(), 9);       // round-trips
62//! ```
63//!
64//! # 4. `#[bitflags]` — single-bit flag sets
65//!
66//! ```
67//! use bnb::bitflags;
68//!
69//! #[bitflags(u8)]
70//! #[derive(Clone, Copy)]
71//! struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, urg: bool }
72//!
73//! let f = TcpFlags::SYN | TcpFlags::ACK;
74//! assert!(f.contains(TcpFlags::SYN));
75//! assert!(f.ack());            // per-flag accessor
76//! assert_eq!(f.bits(), 0b0001_0010);
77//! ```
78//!
79//! # 5. `#[bin]` — a whole message
80//!
81//! `#[bin]` folds the read/write codec and a required-by-default builder over a
82//! struct. Fields can be any `Bits` type (including the `#[bitfield]`/`BitEnum`/
83//! `#[bitflags]` from above), read and written at arbitrary bit offsets.
84//!
85//! ```
86//! use bnb::bin;
87//!
88//! #[bin(big)]
89//! #[derive(Debug, PartialEq)]
90//! struct UdpHeader {
91//!     src_port: u16,
92//!     dst_port: u16,
93//!     length: u16,
94//!     checksum: u16,
95//! }
96//!
97//! let h = UdpHeader::builder()
98//!     .src_port(1234).dst_port(53).length(8).checksum(0)
99//!     .build()
100//!     .unwrap();                       // Err names any field you forgot
101//! let bytes = h.to_bytes().unwrap();   // -> [0x04,0xD2, 0x00,0x35, 0x00,0x08, 0x00,0x00]
102//! assert_eq!(bytes, [0x04, 0xD2, 0x00, 0x35, 0x00, 0x08, 0x00, 0x00]);
103//! assert_eq!(UdpHeader::decode_exact(&bytes).unwrap(), h); // exact inverse
104//! ```
105//!
106//! Next: [`numbers`](super::numbers) for the foundation, or
107//! [`bin_codec`](super::bin_codec) for the codec in depth.