#![cfg_attr(feature = "alloc", doc = "- [`NameBuf`]")]
#![cfg_attr(not(feature = "alloc"), doc = "- `NameBuf`")]
#`<u8>`")]
#![cfg_attr(not(feature = "alloc"), doc = "`Vec<u8>`")]
use core::hash::Hash;
use arrayvec::CapacityError;
use paste::paste;
use crate::{
emit::name::parse_dotted_name,
fmt::{Format, Plain},
view::{BorrowedView, Labels, Name as NameView, View},
};
error!(OwnedNameError, View, Emit);
#[derive(Debug, displaydoc::Display)]
#[prefix_enum_doc_attributes]
pub enum OwnedNameError {
View(crate::view::NameError),
Emit(crate::emit::name::NameError),
Extend(CapacityError),
}
impl From<crate::view::NameError> for OwnedNameError {
fn from(error: crate::view::NameError) -> Self {
Self::View(error)
}
}
impl From<crate::emit::name::NameError> for OwnedNameError {
fn from(error: crate::emit::name::NameError) -> Self {
Self::Emit(error)
}
}
impl From<CapacityError> for OwnedNameError {
fn from(error: CapacityError) -> Self {
Self::Extend(error)
}
}
#[test]
#[rustfmt::skip]
fn test() -> Result<(), OwnedNameError> {
#[cfg(feature = "alloc")]
assert_eq!(NameBuf::from_wire(b"\x05daria\x03daz\x03cat\0")?, "daria.daz.cat.");
#[cfg(feature = "alloc")]
assert_eq!(NameBuf::from_dotted("daria.daz.cat.")?, "daria.daz.cat.");
assert_eq!(NameBufMax::from_wire(b"\x05daria\x03daz\x03cat\0")?, "daria.daz.cat.");
assert_eq!(NameBufMax::from_dotted("daria.daz.cat.")?, "daria.daz.cat.");
Ok(())
}
#[allow(dead_code)]
fn test_static_assert() {}
macro_rules! define_owned_name_type {
{
$(#[$meta:meta])*
$name:ident$([const $N:ident: usize])?($($buffer:tt)+) {
fn try_from_slice($source:ident) {
$try_from_slice:expr
}
fn extend_from_slice($result:ident, $label:ident) {
$extend_from_slice:expr
}
}
} => {paste!{
$(#[$meta])*
#[derive(Clone)]
pub struct $name$(<const $N: usize = 255>)?($($buffer)+);
impl$(<const $N: usize>)? $name$(<$N>)? {
const fn static_assert() {
$(
let _ = AssertValidN::<$N>::CHECK;
struct AssertValidN<const $N: usize>;
impl<const $N: usize> AssertValidN<$N> {
const CHECK: () = if $N > 255 {
panic!("`N` must not be greater than 255")
};
}
)?
}
pub fn from_wire($source: impl AsRef<[u8]>) -> Result<Self, OwnedNameError> {
Self::static_assert();
let $source = $source.as_ref();
let $source = $try_from_slice?;
let _validation = NameView::view(&$source, ..)?;
Ok(Self($source))
}
pub fn from_dotted(input: &str) -> Result<Self, OwnedNameError> {
Self::static_assert();
let mut $result: $($buffer)+ = Default::default();
let mut input = input.as_bytes();
let mut $label = [0u8; 63];
while let Some(($label, rest)) = parse_dotted_name(&mut $label, input)? {
$result.push($label.len() as u8);
$extend_from_slice?;
input = rest;
}
$result.push(0);
Self::from_wire($result)
}
pub fn view<'this>(&'this self) -> NameView<'this> {
NameView::new_unchecked(&self.0, 0..self.0.len())
}
pub fn as_bytes(&self) -> &[u8] {
self.view().as_bytes()
}
pub fn labels_with_null<'this>(&'this self) -> Labels<'this> {
self.view().labels_with_null()
}
pub fn labels_not_null<'this>(&'this self) -> Labels<'this> {
self.view().labels_not_null()
}
pub fn is_subdomain_of(&self, other: &NameView<'_>) -> bool {
self.view().is_subdomain_of(other)
}
pub fn subdomain_distance(&self, other: &NameView<'_>) -> Option<usize> {
self.view().subdomain_distance(other)
}
pub fn parent(&self) -> Option<NameView<'_>> {
self.view().parent()
}
pub fn truncate(&self, labels_not_null: usize) -> NameView<'_> {
self.view().truncate(labels_not_null)
}
}
impl$(<const $N: usize>)? From<NameView<'_>> for $name$(<$N>)? {
fn from(view: NameView<'_>) -> Self {
Self::static_assert();
let mut $result: $($buffer)+ = Default::default();
for $label in view.labels_not_null().flat_map(|$label| $label.value()) {
$result.push($label.len() as u8);
$extend_from_slice.expect("guaranteed by NameView");
}
$result.push(0);
Self::from_wire($result).expect("guaranteed by this function")
}
}
impl$(<const $N: usize>)? core::fmt::Debug for $name$(<$N>)? {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Plain(self).fmt(f)
}
}
impl$(<const $N: usize>)? Format for $name$(<$N>)? {
fn fmt(&self, w: &mut crate::fmt::Wrapper) -> core::fmt::Result {
self.view().fmt(w)
}
}
impl$(<const $N: usize>)? Hash for $name$(<$N>)? {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.view().hash(state)
}
}
impl$(<const $N: usize>)? Ord for $name$(<$N>)? {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.labels_with_null().cmp(other.labels_with_null())
}
}
impl$(<const $N: usize>)? PartialOrd for $name$(<$N>)? {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl$(<const $N: usize>)? Eq for $name$(<$N>)? {}
impl$(<const $N: usize>)? PartialEq for $name$(<$N>)? {
fn eq(&self, other: &Self) -> bool {
self.view().eq(&other.view())
}
}
impl$(<const $N: usize>)? PartialEq<crate::view::Name<'_>> for $name$(<$N>)? {
fn eq(&self, other: &crate::view::Name) -> bool {
self.view().eq(other)
}
}
impl$(<const $N: usize>)? PartialEq<[u8]> for $name$(<$N>)? {
fn eq(&self, other: &[u8]) -> bool {
self.view().eq(other)
}
}
impl$(<const $N: usize>)? PartialEq<&[u8]> for $name$(<$N>)? {
fn eq(&self, other: &&[u8]) -> bool {
self.view().eq(other)
}
}
impl<$(const $N: usize,)? const __N: usize> PartialEq<[u8; __N]> for $name$(<$N>)? {
fn eq(&self, other: &[u8; __N]) -> bool {
self.view().eq(other)
}
}
impl<$(const $N: usize,)? const __N: usize> PartialEq<&[u8; __N]> for $name$(<$N>)? {
fn eq(&self, other: &&[u8; __N]) -> bool {
self.view().eq(other)
}
}
impl$(<const $N: usize>)? PartialEq<str> for $name$(<$N>)? {
fn eq(&self, other: &str) -> bool {
self.view().eq(other)
}
}
impl$(<const $N: usize>)? PartialEq<&str> for $name$(<$N>)? {
fn eq(&self, other: &&str) -> bool {
self.view().eq(other)
}
}
#[cfg(feature = "alloc")]
impl$(<const $N: usize>)? PartialEq<alloc::string::String> for $name$(<$N>)? {
fn eq(&self, other: &alloc::string::String) -> bool {
self.view().eq(other)
}
}
#[cfg(feature = "alloc")]
impl$(<const $N: usize>)? PartialEq<&alloc::string::String> for $name$(<$N>)? {
fn eq(&self, other: &&alloc::string::String) -> bool {
self.view().eq(other)
}
}
}};
}
#[cfg(feature = "alloc")]
define_owned_name_type!(
NameBuf(alloc::vec::Vec<u8>) {
fn try_from_slice(source) {
Ok::<_, OwnedNameError>(alloc::vec::Vec::from(source))
}
fn extend_from_slice(result, label) {
Ok::<_, OwnedNameError>(result.extend_from_slice(label))
}
}
);
pub type NameBufMax = NameBufN<255>;
define_owned_name_type!(
NameBufN[const N: usize](arrayvec::ArrayVec<u8, N>) {
fn try_from_slice(source) {
arrayvec::ArrayVec::try_from(source)
}
fn extend_from_slice(result, label) {
result.try_extend_from_slice(label)
}
}
);