domain/base/iana/
macros.rs
1macro_rules! int_enum {
10 ( $(#[$attr:meta])* =>
11 $ianatype:ident, $inttype:path;
12 $( $(#[$variant_attr:meta])* ( $variant:ident =>
13 $value:expr, $mnemonic:expr) )* ) => {
14 $(#[$attr])*
15 #[derive(Clone, Copy, Debug)]
16 pub enum $ianatype {
17 $( $(#[$variant_attr])* $variant ),*,
18
19 Int($inttype)
21 }
22
23 impl $ianatype {
24 #[must_use]
26 pub const fn from_int(value: $inttype) -> Self {
27 match value {
28 $( $value => $ianatype::$variant ),*,
29 _ => $ianatype::Int(value)
30 }
31 }
32
33 #[must_use]
35 pub const fn to_int(self) -> $inttype {
36 match self {
37 $( $ianatype::$variant => $value ),*,
38 $ianatype::Int(value) => value
39 }
40 }
41
42 #[must_use]
44 pub fn from_mnemonic(m: &[u8]) -> Option<Self> {
45 $(
46 if m.eq_ignore_ascii_case($mnemonic) {
47 return Some($ianatype::$variant)
48 }
49 )*
50 None
51 }
52
53 #[must_use]
58 pub const fn to_mnemonic(self) -> Option<&'static [u8]> {
59 match self {
60 $( $ianatype::$variant => Some($mnemonic) ),*,
61 $ianatype::Int(value) => {
62 match $ianatype::from_int(value) {
63 $ianatype::Int(_) => None,
64 value => value.to_mnemonic()
65 }
66 }
67 }
68 }
69
70 pub fn parse<'a, Octs: AsRef<[u8]> + ?Sized> (
71 parser: &mut octseq::parse::Parser<'a, Octs>
72 ) -> Result<Self, $crate::base::wire::ParseError> {
73 <$inttype as $crate::base::wire::Parse<'a, Octs>>::parse(
74 parser
75 ).map(Self::from_int)
76 }
77
78 pub const COMPOSE_LEN: u16 =
79 <$inttype as $crate::base::wire::Compose>::COMPOSE_LEN;
80
81 pub fn compose<Target: octseq::builder::OctetsBuilder + ?Sized>(
82 &self,
83 target: &mut Target
84 ) -> Result<(), Target::AppendError> {
85 $crate::base::wire::Compose::compose(&self.to_int(), target)
86 }
87 }
88
89
90 impl From<$inttype> for $ianatype {
93 fn from(value: $inttype) -> Self {
94 $ianatype::from_int(value)
95 }
96 }
97
98 impl From<$ianatype> for $inttype {
99 fn from(value: $ianatype) -> Self {
100 value.to_int()
101 }
102 }
103
104 impl<'a> From<&'a $ianatype> for $inttype {
105 fn from(value: &'a $ianatype) -> Self {
106 value.to_int()
107 }
108 }
109
110
111 impl PartialEq for $ianatype {
114 fn eq(&self, other: &Self) -> bool {
115 self.to_int() == other.to_int()
116 }
117 }
118
119 impl PartialEq<$inttype> for $ianatype {
120 fn eq(&self, other: &$inttype) -> bool {
121 self.to_int() == *other
122 }
123 }
124
125 impl PartialEq<$ianatype> for $inttype {
126 fn eq(&self, other: &$ianatype) -> bool {
127 *self == other.to_int()
128 }
129 }
130
131 impl Eq for $ianatype { }
132
133
134 impl PartialOrd for $ianatype {
137 fn partial_cmp(
138 &self, other: &Self
139 ) -> Option<core::cmp::Ordering> {
140 Some(self.cmp(other))
141 }
142 }
143
144 impl PartialOrd<$inttype> for $ianatype {
145 fn partial_cmp(
146 &self, other: &$inttype
147 ) -> Option<core::cmp::Ordering> {
148 self.to_int().partial_cmp(other)
149 }
150 }
151
152 impl PartialOrd<$ianatype> for $inttype {
153 fn partial_cmp(
154 &self, other: &$ianatype
155 ) -> Option<core::cmp::Ordering> {
156 self.partial_cmp(&other.to_int())
157 }
158 }
159
160 impl Ord for $ianatype {
161 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
162 self.to_int().cmp(&other.to_int())
163 }
164 }
165
166
167 impl core::hash::Hash for $ianatype {
170 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
171 self.to_int().hash(state)
172 }
173 }
174 }
175}
176
177macro_rules! int_enum_str_decimal {
229 ($ianatype:ident, $inttype:ident) => {
230 impl $ianatype {
231 #[must_use]
232 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
233 core::str::from_utf8(bytes)
234 .ok()
235 .and_then(|r| r.parse().ok().map($ianatype::from_int))
236 }
237 }
238
239 impl core::str::FromStr for $ianatype {
240 type Err = core::num::ParseIntError;
241
242 fn from_str(s: &str) -> Result<Self, Self::Err> {
243 s.parse().map($ianatype::from_int)
244 }
245 }
246
247 scan_impl!($ianatype);
248
249 impl core::fmt::Display for $ianatype {
250 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
251 write!(f, "{}", self.to_int())
252 }
253 }
254
255 #[cfg(feature = "serde")]
256 impl serde::Serialize for $ianatype {
257 fn serialize<S: serde::Serializer>(
258 &self,
259 serializer: S,
260 ) -> Result<S::Ok, S::Error> {
261 self.to_int().serialize(serializer)
262 }
263 }
264
265 #[cfg(feature = "serde")]
266 impl<'de> serde::Deserialize<'de> for $ianatype {
267 fn deserialize<D: serde::Deserializer<'de>>(
268 deserializer: D,
269 ) -> Result<Self, D::Error> {
270 $inttype::deserialize(deserializer).map(Into::into)
271 }
272 }
273 };
274}
275
276macro_rules! int_enum_str_with_decimal {
290 ($ianatype:ident, $inttype:ident, $error:expr) => {
291 impl $ianatype {
292 #[must_use]
293 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
294 $ianatype::from_mnemonic(bytes).or_else(|| {
295 core::str::from_utf8(bytes)
296 .ok()
297 .and_then(|r| r.parse().ok().map($ianatype::from_int))
298 })
299 }
300 }
301
302 impl core::str::FromStr for $ianatype {
303 type Err = FromStrError;
304
305 fn from_str(s: &str) -> Result<Self, Self::Err> {
306 match $ianatype::from_mnemonic(s.as_bytes()) {
309 Some(res) => Ok(res),
310 None => {
311 if let Ok(res) = s.parse() {
312 Ok($ianatype::from_int(res))
313 } else {
314 Err(FromStrError)
315 }
316 }
317 }
318 }
319 }
320
321 impl core::fmt::Display for $ianatype {
322 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
323 use core::fmt::Write;
324
325 match self.to_mnemonic() {
326 Some(m) => {
327 for ch in m {
328 f.write_char(*ch as char)?
329 }
330 Ok(())
331 }
332 None => {
333 write!(f, "{}", self.to_int())
334 }
335 }
336 }
337 }
338
339 scan_impl!($ianatype);
340
341 #[cfg(feature = "serde")]
342 impl serde::Serialize for $ianatype {
343 fn serialize<S: serde::Serializer>(
344 &self,
345 serializer: S,
346 ) -> Result<S::Ok, S::Error> {
347 if serializer.is_human_readable() {
348 match self
349 .to_mnemonic()
350 .and_then(|value| core::str::from_utf8(value).ok())
351 {
352 Some(value) => value.serialize(serializer),
353 None => self.to_int().serialize(serializer),
354 }
355 } else {
356 self.to_int().serialize(serializer)
357 }
358 }
359 }
360
361 #[cfg(feature = "serde")]
362 impl<'de> serde::Deserialize<'de> for $ianatype {
363 fn deserialize<D: serde::Deserializer<'de>>(
364 deserializer: D,
365 ) -> Result<Self, D::Error> {
366 use crate::base::serde::DeserializeNativeOrStr;
367
368 $inttype::deserialize_native_or_str(deserializer)
369 }
370 }
371
372 from_str_error!($error);
373 };
374}
375
376macro_rules! int_enum_str_with_prefix {
385 ($ianatype:ident, $str_prefix:expr, $u8_prefix:expr, $inttype:ident,
386 $error:expr) => {
387 impl $ianatype {
388 #[must_use]
389 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
390 $ianatype::from_mnemonic(bytes).or_else(|| {
391 if bytes.len() <= $u8_prefix.len() {
392 return None;
393 }
394 let (l, r) = bytes.split_at($u8_prefix.len());
395 if !l.eq_ignore_ascii_case($u8_prefix) {
396 return None;
397 }
398 let r = match core::str::from_utf8(r) {
399 Ok(r) => r,
400 Err(_) => return None,
401 };
402 r.parse().ok().map($ianatype::from_int)
403 })
404 }
405 }
406
407 impl core::str::FromStr for $ianatype {
408 type Err = FromStrError;
409
410 fn from_str(s: &str) -> Result<Self, Self::Err> {
411 match $ianatype::from_mnemonic(s.as_bytes()) {
414 Some(res) => Ok(res),
415 None => {
416 if let Some((n, _)) =
417 s.char_indices().nth($str_prefix.len())
418 {
419 let (l, r) = s.split_at(n);
420 if l.eq_ignore_ascii_case($str_prefix) {
421 let value = match r.parse() {
422 Ok(x) => x,
423 Err(..) => return Err(FromStrError),
424 };
425 Ok($ianatype::from_int(value))
426 } else {
427 Err(FromStrError)
428 }
429 } else {
430 Err(FromStrError)
431 }
432 }
433 }
434 }
435 }
436
437 impl core::fmt::Display for $ianatype {
438 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
439 use core::fmt::Write;
440
441 match self.to_mnemonic() {
442 Some(m) => {
443 for ch in m {
444 f.write_char(*ch as char)?
445 }
446 Ok(())
447 }
448 None => {
449 write!(f, "{}{}", $str_prefix, self.to_int())
450 }
451 }
452 }
453 }
454
455 scan_impl!($ianatype);
456
457 #[cfg(feature = "serde")]
458 impl serde::Serialize for $ianatype {
459 fn serialize<S: serde::Serializer>(
460 &self,
461 serializer: S,
462 ) -> Result<S::Ok, S::Error> {
463 if serializer.is_human_readable() {
464 serializer.collect_str(&format_args!("{}", self))
465 } else {
466 self.to_int().serialize(serializer)
467 }
468 }
469 }
470
471 #[cfg(feature = "serde")]
472 impl<'de> serde::Deserialize<'de> for $ianatype {
473 fn deserialize<D: serde::Deserializer<'de>>(
474 deserializer: D,
475 ) -> Result<Self, D::Error> {
476 use crate::base::serde::DeserializeNativeOrStr;
477
478 $inttype::deserialize_native_or_str(deserializer)
479 }
480 }
481
482 from_str_error!($error);
483 };
484}
485
486macro_rules! scan_impl {
487 ($ianatype:ident) => {
488 impl $ianatype {
489 pub fn scan<S: $crate::base::scan::Scanner>(
490 scanner: &mut S,
491 ) -> Result<Self, S::Error> {
492 scanner.scan_ascii_str(|s| {
493 core::str::FromStr::from_str(s).map_err(|_| {
494 $crate::base::scan::ScannerError::custom(concat!(
495 "expected ",
496 stringify!($ianatype)
497 ))
498 })
499 })
500 }
501 }
502 };
503}
504
505macro_rules! from_str_error {
506 ($description:expr) => {
507 #[derive(Clone, Debug)]
508 pub struct FromStrError;
509
510 #[cfg(feature = "std")]
511 impl std::error::Error for FromStrError {
512 fn description(&self) -> &str {
513 $description
514 }
515 }
516
517 impl core::fmt::Display for FromStrError {
518 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
519 $description.fmt(f)
520 }
521 }
522 };
523}