pub use crate::core::error::{
ClassFromStrError, OpcodeRangeError, RcodeRangeError, SerialAdditionError, TtlFromStrError,
TypeFromStrError,
};
pub(crate) mod r#const;
use self::r#const::{CLASS, RCODE, TYPE};
use core::{fmt::Debug, str::FromStr};
pub mod error {
error!(OpcodeRangeError);
#[derive(Debug, displaydoc::Display)]
pub struct OpcodeRangeError(pub(crate) u8);
error!(RcodeRangeError);
#[derive(Debug, displaydoc::Display)]
pub enum RcodeRangeError {
Extended(u16),
Basic(u8),
}
error!(TypeFromStrError);
#[derive(Debug, displaydoc::Display)]
pub struct TypeFromStrError;
error!(ClassFromStrError);
#[derive(Debug, displaydoc::Display)]
pub struct ClassFromStrError;
error!(TtlFromStrError);
#[derive(Debug, displaydoc::Display)]
pub struct TtlFromStrError;
error!(SerialAdditionError);
#[derive(Debug, displaydoc::Display, PartialEq)]
pub struct SerialAdditionError;
}
#[derive(Debug, Clone, PartialEq)]
pub struct Opcode(u8);
#[derive(Debug, Clone, PartialEq)]
pub struct Rcode(u16);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Type(u16);
#[derive(Debug, Clone, PartialEq)]
pub struct Class(u16);
#[derive(Debug, Clone)]
pub struct Ttl(u32);
#[derive(Debug, Clone, PartialEq)]
pub struct Serial(u32);
impl Opcode {
pub const fn new(value: u8) -> Result<Self, OpcodeRangeError> {
if value > 0xF {
return Err(OpcodeRangeError(value));
}
Ok(Self(value))
}
pub const fn value(&self) -> u8 {
self.0
}
}
impl Rcode {
pub const fn new(value: u16) -> Result<Self, RcodeRangeError> {
if value > 0xFFF {
return Err(RcodeRangeError::Extended(value));
}
Ok(Self(value))
}
pub const fn from_basic_extended(
basic_part: u8,
extended_part: u8,
) -> Result<Self, RcodeRangeError> {
if basic_part > 0xF {
return Err(RcodeRangeError::Basic(basic_part));
}
let basic_part = basic_part as u16;
let extended_part = extended_part as u16;
Self::new(extended_part << 4 | basic_part)
}
pub const fn name_opt(&self) -> Option<&'static str> {
RCODE.to_name_opt(self.value())
}
pub const fn name_tsig(&self) -> Option<&'static str> {
RCODE.to_name_tsig(self.value())
}
pub const fn value(&self) -> u16 {
self.0
}
pub const fn basic_part(&self) -> u8 {
(self.0 & 0xF) as u8
}
pub const fn extended_part(&self) -> u8 {
(self.0 >> 4) as u8
}
}
impl Type {
pub const fn new(value: u16) -> Self {
Self(value)
}
pub const fn value(&self) -> u16 {
self.0
}
}
impl Class {
pub const fn new(value: u16) -> Self {
Self(value)
}
pub const fn value(&self) -> u16 {
self.0
}
}
impl Ttl {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn value(&self) -> u32 {
self.0
}
pub(crate) const fn edns_version(&self) -> u8 {
(self.value() >> 16 & 0xFF) as _
}
}
impl Serial {
pub const fn new(value: u32) -> Self {
Self(value)
}
pub const fn value(&self) -> u32 {
self.0
}
}
impl FromStr for Type {
type Err = TypeFromStrError;
fn from_str(source: &str) -> Result<Self, Self::Err> {
if let Some(value) = TYPE.to_number(&source) {
return Ok(Type(value));
}
if source.starts_with("TYPE") {
return Ok(Type(
u16::from_str_radix(&source[4..], 10).map_err(|_| TypeFromStrError)?,
));
}
Err(TypeFromStrError)
}
}
impl FromStr for Class {
type Err = ClassFromStrError;
fn from_str(source: &str) -> Result<Self, Self::Err> {
if let Some(value) = CLASS.to_number(&source) {
return Ok(Class(value));
}
if source.starts_with("CLASS") {
return Ok(Class(
u16::from_str_radix(&source[5..], 10).map_err(|_| ClassFromStrError)?,
));
}
Err(ClassFromStrError)
}
}
#[cfg(all(test, feature = "bench"))]
mod bench {
mod parse {
extern crate test;
use test::Bencher;
use crate::core::{Class, Type};
#[bench]
fn r#type(bencher: &mut Bencher) {
bencher.iter(|| "cname".parse::<Type>());
}
#[bench]
fn class(bencher: &mut Bencher) {
bencher.iter(|| "hs".parse::<Class>());
}
}
}