Skip to main content

bnb/guide/
flags.rs

1//! `#[bitflags]` — a named set of single-bit flags with set algebra.
2//!
3//! Each `bool` field is one flag, assigned a bit by declaration order (LSB-first: the
4//! first field is `1 << 0`), or pinned with `#[flag(N)]`.
5//!
6//! ```
7//! use bnb::bitflags;
8//!
9//! #[bitflags(u8)]
10//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
11//! struct TcpFlags {
12//!     fin: bool,            // bit 0
13//!     syn: bool,            // bit 1
14//!     rst: bool,            // bit 2
15//!     psh: bool,            // bit 3
16//!     ack: bool,            // bit 4
17//!     #[flag(7)] cwr: bool, // pinned to bit 7
18//! }
19//!
20//! assert_eq!(TcpFlags::SYN.bits(), 0b0000_0010); // an UPPERCASE const per flag
21//! assert_eq!(TcpFlags::CWR.bits(), 0b1000_0000);
22//! ```
23//!
24//! # Set algebra
25//!
26//! Flags compose with the bitwise operators and the named set operations:
27//!
28//! ```
29//! # use bnb::bitflags;
30//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
31//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
32//! let f = TcpFlags::SYN | TcpFlags::ACK;
33//! assert!(f.contains(TcpFlags::SYN));
34//! assert!(f.intersects(TcpFlags::ACK | TcpFlags::FIN));
35//! assert_eq!((f - TcpFlags::SYN), TcpFlags::ACK);   // difference
36//! assert_eq!((f & TcpFlags::SYN), TcpFlags::SYN);   // intersection
37//! assert!(TcpFlags::empty().is_empty());
38//! ```
39//!
40//! # Per-flag accessors and iteration
41//!
42//! ```
43//! # use bnb::bitflags;
44//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
45//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
46//! let mut f = TcpFlags::empty().with_syn(true).with_ack(true);
47//! assert!(f.syn() && f.ack() && !f.fin());
48//! f.set_ack(false);
49//! assert!(!f.ack());
50//! let set: Vec<_> = f.iter().collect();            // the single-bit flags that are set
51//! assert_eq!(set, vec![TcpFlags::SYN]);
52//! ```
53//!
54//! # Unknown bits: retain vs. truncate
55//!
56//! Like a catch-all enum, a flag set is dual-use: `from_bits` **retains** bits that
57//! don't correspond to a declared flag (so a parser round-trips unknown bits), while
58//! `from_bits_truncate` drops them.
59//!
60//! ```
61//! # use bnb::bitflags;
62//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
63//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
64//! let raw = 0b0010_0010; // SYN set, plus an undefined bit 5
65//! assert_eq!(TcpFlags::from_bits(raw).bits(), 0b0010_0010);          // retained
66//! assert_eq!(TcpFlags::from_bits_truncate(raw).bits(), 0b0000_0010); // dropped
67//! ```
68//!
69//! # Nesting in a bitfield
70//!
71//! A flag set implements [`Bits`](crate::Bits), so it drops into a `#[bitfield]` or a
72//! `#[bin]` message as a field of its backing width:
73//!
74//! ```
75//! use bnb::{bitfield, bitflags, u4};
76//!
77//! #[bitflags(u8)]
78//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
79//! struct Caps { dnssec: bool, recursion: bool, compression: bool, extended: bool }
80//!
81//! #[bitfield(u16, bits = msb)]
82//! #[derive(Clone, Copy)]
83//! struct Header { version: u4, caps: Caps }   // 4 + 8 = 12 bits (in a u16)
84//!
85//! let h = Header::new().with_version(u4::new(1)).with_caps(Caps::DNSSEC | Caps::RECURSION);
86//! assert!(h.caps().dnssec());
87//! ```