Skip to main content

mdns_proto/wire/
flags.rs

1//! Packed 16-bit DNS header flags field (RFC 1035 §4.1.1, RFC 6762 §18.6-18.12).
2
3use super::{Opcode, ResponseCode};
4
5const QR_BIT: u16 = 1 << 15;
6const OPCODE_SHIFT: u32 = 11;
7const OPCODE_MASK: u16 = 0b1111 << OPCODE_SHIFT;
8const AA_BIT: u16 = 1 << 10;
9const TC_BIT: u16 = 1 << 9;
10const RD_BIT: u16 = 1 << 8;
11const RA_BIT: u16 = 1 << 7;
12const RCODE_MASK: u16 = 0b1111;
13
14/// Packed 16-bit DNS header flags field.
15#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)]
16pub struct Flags {
17  bits: u16,
18}
19
20impl Flags {
21  /// Empty flags (all zero — query, no error).
22  #[inline(always)]
23  pub const fn new() -> Self {
24    Self { bits: 0 }
25  }
26
27  /// Constructs from raw wire bits.
28  #[inline(always)]
29  pub const fn from_u16(bits: u16) -> Self {
30    Self { bits }
31  }
32
33  /// Returns the raw wire bits.
34  #[inline(always)]
35  pub const fn to_u16(&self) -> u16 {
36    self.bits
37  }
38
39  /// `true` if this is a response (QR bit set).
40  #[inline(always)]
41  pub const fn is_response(&self) -> bool {
42    self.bits & QR_BIT != 0
43  }
44
45  /// Opcode (4 bits).
46  #[inline(always)]
47  pub const fn opcode(&self) -> Opcode {
48    Opcode::from_u8(((self.bits & OPCODE_MASK) >> OPCODE_SHIFT) as u8)
49  }
50
51  /// `true` if authoritative answer.
52  #[inline(always)]
53  pub const fn is_authoritative(&self) -> bool {
54    self.bits & AA_BIT != 0
55  }
56
57  /// `true` if truncated (TC bit).
58  #[inline(always)]
59  pub const fn is_truncated(&self) -> bool {
60    self.bits & TC_BIT != 0
61  }
62
63  /// `true` if recursion desired (RD bit).
64  #[inline(always)]
65  pub const fn is_recursion_desired(&self) -> bool {
66    self.bits & RD_BIT != 0
67  }
68
69  /// `true` if recursion available (RA bit).
70  #[inline(always)]
71  pub const fn is_recursion_available(&self) -> bool {
72    self.bits & RA_BIT != 0
73  }
74
75  /// Response code (4 bits).
76  #[inline(always)]
77  pub const fn response_code(&self) -> ResponseCode {
78    ResponseCode::from_u8((self.bits & RCODE_MASK) as u8)
79  }
80
81  // ── Mutators (per §3 rust-type-conventions) ────────────────────
82
83  /// Sets the QR bit (this is a response).
84  #[inline(always)]
85  pub const fn set_response(&mut self) -> &mut Self {
86    self.bits |= QR_BIT;
87    self
88  }
89  /// Same as [`Self::set_response`] but consuming.
90  #[inline(always)]
91  pub const fn with_response(mut self) -> Self {
92    self.bits |= QR_BIT;
93    self
94  }
95  /// Clears the QR bit (this is a query).
96  #[inline(always)]
97  pub const fn clear_response(&mut self) -> &mut Self {
98    self.bits &= !QR_BIT;
99    self
100  }
101
102  /// Sets the opcode.
103  #[inline(always)]
104  pub const fn set_opcode(&mut self, op: Opcode) -> &mut Self {
105    self.bits &= !OPCODE_MASK;
106    self.bits |= ((op.to_u8() as u16) << OPCODE_SHIFT) & OPCODE_MASK;
107    self
108  }
109  /// Consuming version of [`Self::set_opcode`].
110  #[inline(always)]
111  pub const fn with_opcode(mut self, op: Opcode) -> Self {
112    self.bits &= !OPCODE_MASK;
113    self.bits |= ((op.to_u8() as u16) << OPCODE_SHIFT) & OPCODE_MASK;
114    self
115  }
116
117  /// Sets the AA bit (authoritative answer).
118  #[inline(always)]
119  pub const fn set_authoritative(&mut self) -> &mut Self {
120    self.bits |= AA_BIT;
121    self
122  }
123  /// Consuming version.
124  #[inline(always)]
125  pub const fn with_authoritative(mut self) -> Self {
126    self.bits |= AA_BIT;
127    self
128  }
129  /// Clears the AA bit.
130  #[inline(always)]
131  pub const fn clear_authoritative(&mut self) -> &mut Self {
132    self.bits &= !AA_BIT;
133    self
134  }
135
136  /// Sets the TC bit.
137  #[inline(always)]
138  pub const fn set_truncated(&mut self) -> &mut Self {
139    self.bits |= TC_BIT;
140    self
141  }
142  /// Consuming version.
143  #[inline(always)]
144  pub const fn with_truncated(mut self) -> Self {
145    self.bits |= TC_BIT;
146    self
147  }
148  /// Clears the TC bit.
149  #[inline(always)]
150  pub const fn clear_truncated(&mut self) -> &mut Self {
151    self.bits &= !TC_BIT;
152    self
153  }
154
155  /// Sets the response code.
156  #[inline(always)]
157  pub const fn set_response_code(&mut self, rc: ResponseCode) -> &mut Self {
158    self.bits &= !RCODE_MASK;
159    self.bits |= (rc.to_u8() as u16) & RCODE_MASK;
160    self
161  }
162  /// Consuming version.
163  #[inline(always)]
164  pub const fn with_response_code(mut self, rc: ResponseCode) -> Self {
165    self.bits &= !RCODE_MASK;
166    self.bits |= (rc.to_u8() as u16) & RCODE_MASK;
167    self
168  }
169}
170
171#[cfg(test)]
172#[allow(clippy::unwrap_used)]
173mod tests;