Skip to main content

Module quick_start

Module quick_start 

Source
Expand description

A five-minute tour of every macro.

Each block below is a complete, runnable example. Together they cover the whole surface; the later guide pages go deep on each.

§1. Arbitrary-width integers

u1..u127 are range-checked sub-byte integers — the building blocks of packed fields. The native widths (u8/u16/…) are the standard library’s.

use bnb::{u4, u12};

let nibble = u4::new(0xA);          // panics if > 0xF
assert_eq!(nibble.value(), 0xA);
assert!(u4::try_new(0x10).is_err()); // checked construction
assert_eq!(u12::MAX.value(), 0xFFF);

§2. #[bitfield] — pack typed fields into one integer

use bnb::{bitfield, u4};

// A u16 split into three fields, most-significant-first (RFC order).
#[bitfield(u16, bits = msb, bytes = big)]
#[derive(Clone, Copy)]
struct VlanTag {
    pcp: u4,   // high nibble
    dei: bool,
    vid: bnb::u11,
}

let tag = VlanTag::new().with_pcp(u4::new(5)).with_dei(true).with_vid(bnb::u11::new(100));
assert_eq!(tag.pcp().value(), 5);
assert!(tag.dei());
assert_eq!(tag.vid().value(), 100);
assert_eq!(tag.to_be_bytes().len(), 2);

§3. #[derive(BitEnum)] — enum ⇄ integer

A #[catch_all] variant preserves unknown values, so a parser never rejects representable input (the dual-use convention).

use bnb::{BitEnum, Bits, u4};

#[derive(BitEnum, Clone, Copy, Debug, PartialEq, Eq)]
#[bit_enum(u4)]
enum RCode {
    NoError,
    FormErr,
    ServFail,
    #[catch_all]
    Other(u4),
}

assert_eq!(RCode::from_bits(2), RCode::ServFail);
assert_eq!(RCode::from_bits(9), RCode::Other(u4::new(9))); // unknown, preserved
assert_eq!(RCode::Other(u4::new(9)).into_bits(), 9);       // round-trips

§4. #[bitflags] — single-bit flag sets

use bnb::bitflags;

#[bitflags(u8)]
#[derive(Clone, Copy)]
struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, urg: bool }

let f = TcpFlags::SYN | TcpFlags::ACK;
assert!(f.contains(TcpFlags::SYN));
assert!(f.ack());            // per-flag accessor
assert_eq!(f.bits(), 0b0001_0010);

§5. #[bin] — a whole message

#[bin] folds the read/write codec and a required-by-default builder over a struct. Fields can be any Bits type (including the #[bitfield]/BitEnum/ #[bitflags] from above), read and written at arbitrary bit offsets.

use bnb::bin;

#[bin(big)]
#[derive(Debug, PartialEq)]
struct UdpHeader {
    src_port: u16,
    dst_port: u16,
    length: u16,
    checksum: u16,
}

let h = UdpHeader::builder()
    .src_port(1234).dst_port(53).length(8).checksum(0)
    .build()
    .unwrap();                       // Err names any field you forgot
let bytes = h.to_bytes().unwrap();   // -> [0x04,0xD2, 0x00,0x35, 0x00,0x08, 0x00,0x00]
assert_eq!(bytes, [0x04, 0xD2, 0x00, 0x35, 0x00, 0x08, 0x00, 0x00]);
assert_eq!(UdpHeader::decode_exact(&bytes).unwrap(), h); // exact inverse

Next: numbers for the foundation, or bin_codec for the codec in depth.