1pub use crate::core::error::{
4 ClassFromStrError, OpcodeRangeError, RcodeRangeError, SerialAdditionError, TtlFromStrError,
5 TypeFromStrError,
6};
7
8pub(crate) mod r#const;
9
10use self::r#const::{CLASS, RCODE, TYPE};
11
12use core::{fmt::Debug, str::FromStr};
13
14pub mod error {
15 error!(OpcodeRangeError);
16 #[derive(Debug, displaydoc::Display)]
17 pub struct OpcodeRangeError(pub(crate) u8);
19
20 error!(RcodeRangeError);
21 #[derive(Debug, displaydoc::Display)]
22 pub enum RcodeRangeError {
24 Extended(u16),
26
27 Basic(u8),
29 }
30
31 error!(TypeFromStrError);
32 #[derive(Debug, displaydoc::Display)]
33 pub struct TypeFromStrError;
35
36 error!(ClassFromStrError);
37 #[derive(Debug, displaydoc::Display)]
38 pub struct ClassFromStrError;
40
41 error!(TtlFromStrError);
42 #[derive(Debug, displaydoc::Display)]
43 pub struct TtlFromStrError;
45
46 error!(SerialAdditionError);
47 #[derive(Debug, displaydoc::Display, PartialEq)]
48 pub struct SerialAdditionError;
50}
51
52#[derive(Debug, Clone, PartialEq)]
53pub struct Opcode(u8);
54
55#[derive(Debug, Clone, PartialEq)]
56pub struct Rcode(u16);
57
58#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
59pub struct Type(u16);
60
61#[derive(Debug, Clone, PartialEq)]
62pub struct Class(u16);
63
64#[derive(Debug, Clone)]
65pub struct Ttl(u32);
66
67#[derive(Debug, Clone, PartialEq)]
68pub struct Serial(u32);
69
70impl Opcode {
71 pub const fn new(value: u8) -> Result<Self, OpcodeRangeError> {
72 if value > 0xF {
73 return Err(OpcodeRangeError(value));
74 }
75
76 Ok(Self(value))
77 }
78
79 pub const fn value(&self) -> u8 {
80 self.0
81 }
82}
83
84impl Rcode {
85 pub const fn new(value: u16) -> Result<Self, RcodeRangeError> {
86 if value > 0xFFF {
87 return Err(RcodeRangeError::Extended(value));
88 }
89
90 Ok(Self(value))
91 }
92
93 pub const fn from_basic_extended(
94 basic_part: u8,
95 extended_part: u8,
96 ) -> Result<Self, RcodeRangeError> {
97 if basic_part > 0xF {
98 return Err(RcodeRangeError::Basic(basic_part));
99 }
100
101 let basic_part = basic_part as u16;
103 let extended_part = extended_part as u16;
104
105 Self::new(extended_part << 4 | basic_part)
106 }
107
108 pub const fn name_opt(&self) -> Option<&'static str> {
109 RCODE.to_name_opt(self.value())
110 }
111
112 pub const fn name_tsig(&self) -> Option<&'static str> {
113 RCODE.to_name_tsig(self.value())
114 }
115
116 pub const fn value(&self) -> u16 {
117 self.0
118 }
119
120 pub const fn basic_part(&self) -> u8 {
121 (self.0 & 0xF) as u8
124 }
125
126 pub const fn extended_part(&self) -> u8 {
127 (self.0 >> 4) as u8
130 }
131}
132
133impl Type {
134 pub const fn new(value: u16) -> Self {
135 Self(value)
136 }
137
138 pub const fn value(&self) -> u16 {
139 self.0
140 }
141}
142
143impl Class {
144 pub const fn new(value: u16) -> Self {
145 Self(value)
146 }
147
148 pub const fn value(&self) -> u16 {
149 self.0
150 }
151}
152
153impl Ttl {
154 pub const fn new(value: u32) -> Self {
155 Self(value)
156 }
157
158 pub const fn value(&self) -> u32 {
159 self.0
160 }
161
162 pub(crate) const fn edns_version(&self) -> u8 {
163 (self.value() >> 16 & 0xFF) as _
164 }
165}
166
167impl Serial {
168 pub const fn new(value: u32) -> Self {
169 Self(value)
170 }
171
172 pub const fn value(&self) -> u32 {
173 self.0
174 }
175}
176
177impl FromStr for Type {
178 type Err = TypeFromStrError;
179
180 fn from_str(source: &str) -> Result<Self, Self::Err> {
181 if let Some(value) = TYPE.to_number(&source) {
182 return Ok(Type(value));
183 }
184
185 if source.starts_with("TYPE") {
187 return Ok(Type(
188 u16::from_str_radix(&source[4..], 10).map_err(|_| TypeFromStrError)?,
189 ));
190 }
191
192 Err(TypeFromStrError)
193 }
194}
195
196impl FromStr for Class {
197 type Err = ClassFromStrError;
198
199 fn from_str(source: &str) -> Result<Self, Self::Err> {
200 if let Some(value) = CLASS.to_number(&source) {
201 return Ok(Class(value));
202 }
203
204 if source.starts_with("CLASS") {
206 return Ok(Class(
207 u16::from_str_radix(&source[5..], 10).map_err(|_| ClassFromStrError)?,
208 ));
209 }
210
211 Err(ClassFromStrError)
212 }
213}
214
215#[cfg(all(test, feature = "bench"))]
216mod bench {
217 mod parse {
218 extern crate test;
219
220 use test::Bencher;
221
222 use crate::core::{Class, Type};
223
224 #[bench]
225 fn r#type(bencher: &mut Bencher) {
226 bencher.iter(|| "cname".parse::<Type>());
227 }
228
229 #[bench]
230 fn class(bencher: &mut Bencher) {
231 bencher.iter(|| "hs".parse::<Class>());
232 }
233 }
234}