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
//! `#[bitflags]` — a named set of single-bit flags with set algebra.
//!
//! Each `bool` field is one flag, assigned a bit by declaration order (LSB-first: the
//! first field is `1 << 0`), or pinned with `#[flag(N)]`.
//!
//! ```
//! use bnb::bitflags;
//!
//! #[bitflags(u8)]
//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! struct TcpFlags {
//! fin: bool, // bit 0
//! syn: bool, // bit 1
//! rst: bool, // bit 2
//! psh: bool, // bit 3
//! ack: bool, // bit 4
//! #[flag(7)] cwr: bool, // pinned to bit 7
//! }
//!
//! assert_eq!(TcpFlags::SYN.bits(), 0b0000_0010); // an UPPERCASE const per flag
//! assert_eq!(TcpFlags::CWR.bits(), 0b1000_0000);
//! ```
//!
//! # Set algebra
//!
//! Flags compose with the bitwise operators and the named set operations:
//!
//! ```
//! # use bnb::bitflags;
//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
//! let f = TcpFlags::SYN | TcpFlags::ACK;
//! assert!(f.contains(TcpFlags::SYN));
//! assert!(f.intersects(TcpFlags::ACK | TcpFlags::FIN));
//! assert_eq!((f - TcpFlags::SYN), TcpFlags::ACK); // difference
//! assert_eq!((f & TcpFlags::SYN), TcpFlags::SYN); // intersection
//! assert!(TcpFlags::empty().is_empty());
//! ```
//!
//! # Per-flag accessors and iteration
//!
//! ```
//! # use bnb::bitflags;
//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
//! let mut f = TcpFlags::empty().with_syn(true).with_ack(true);
//! assert!(f.syn() && f.ack() && !f.fin());
//! f.set_ack(false);
//! assert!(!f.ack());
//! let set: Vec<_> = f.iter().collect(); // the single-bit flags that are set
//! assert_eq!(set, vec![TcpFlags::SYN]);
//! ```
//!
//! # Unknown bits: retain vs. truncate
//!
//! Like a catch-all enum, a flag set is dual-use: `from_bits` **retains** bits that
//! don't correspond to a declared flag (so a parser round-trips unknown bits), while
//! `from_bits_truncate` drops them.
//!
//! ```
//! # use bnb::bitflags;
//! # #[bitflags(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! # struct TcpFlags { fin: bool, syn: bool, rst: bool, psh: bool, ack: bool, #[flag(7)] cwr: bool }
//! let raw = 0b0010_0010; // SYN set, plus an undefined bit 5
//! assert_eq!(TcpFlags::from_bits(raw).bits(), 0b0010_0010); // retained
//! assert_eq!(TcpFlags::from_bits_truncate(raw).bits(), 0b0000_0010); // dropped
//! ```
//!
//! # Nesting in a bitfield
//!
//! A flag set implements [`Bits`](crate::Bits), so it drops into a `#[bitfield]` or a
//! `#[bin]` message as a field of its backing width:
//!
//! ```
//! use bnb::{bitfield, bitflags, u4};
//!
//! #[bitflags(u8)]
//! #[derive(Clone, Copy, Debug, PartialEq, Eq)]
//! struct Caps { dnssec: bool, recursion: bool, compression: bool, extended: bool }
//!
//! #[bitfield(u16, bits = msb)]
//! #[derive(Clone, Copy)]
//! struct Header { version: u4, caps: Caps } // 4 + 8 = 12 bits (in a u16)
//!
//! let h = Header::new().with_version(u4::new(1)).with_caps(Caps::DNSSEC | Caps::RECURSION);
//! assert!(h.caps().dnssec());
//! ```