use domain_macros::*;
use crate::new::base::{
parse::{ParseMessageBytes, SplitMessageBytes},
wire::{ParseBytes, ParseError, SplitBytes},
};
use super::Label;
#[derive(AsBytes)]
#[repr(transparent)]
pub struct UnparsedName([u8]);
impl UnparsedName {
pub const MAX_SIZE: usize = 256;
pub const ROOT: &'static Self = {
unsafe { Self::from_bytes_unchecked(&[0u8]) }
};
}
impl UnparsedName {
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
core::mem::transmute(bytes)
}
pub unsafe fn from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut Self {
core::mem::transmute(bytes)
}
}
impl UnparsedName {
#[allow(clippy::len_without_is_empty)]
pub const fn len(&self) -> usize {
self.0.len()
}
pub const fn is_root(&self) -> bool {
self.0.len() == 1
}
pub const fn pointer_value(&self) -> Option<u16> {
if let &[hi @ 0xC0..=0xFF, lo] = self.as_bytes() {
Some(u16::from_be_bytes([hi, lo]) & 0x3FFF)
} else {
None
}
}
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl UnparsedName {
pub fn split_first(&self) -> Option<(&Label, &Self)> {
let (label, rest) = <&Label>::split_bytes(self.as_bytes())
.ok()
.filter(|(label, _)| !label.is_root())?;
Some((label, unsafe { Self::from_bytes_unchecked(rest) }))
}
}
impl<'a> SplitMessageBytes<'a> for &'a UnparsedName {
fn split_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
let bytes = &contents[start..];
let mut offset = 0;
while offset < 255 {
match *bytes.get(offset..).ok_or(ParseError)? {
[0, ..] => {
offset += 1;
let bytes = &bytes[..offset];
return Ok((
unsafe { UnparsedName::from_bytes_unchecked(bytes) },
start + offset,
));
}
[l @ 1..=63, ref rest @ ..] if rest.len() >= l as usize => {
offset += 1 + l as usize;
}
[hi, lo, ..] if hi >= 0xC0 => {
let ptr = u16::from_be_bytes([hi, lo]);
if usize::from(ptr - 0xC000) >= start {
return Err(ParseError);
}
offset += 2;
let bytes = &bytes[..offset];
return Ok((
unsafe { UnparsedName::from_bytes_unchecked(bytes) },
start + offset,
));
}
_ => return Err(ParseError),
}
}
Err(ParseError)
}
}
impl<'a> ParseMessageBytes<'a> for &'a UnparsedName {
fn parse_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<Self, ParseError> {
match Self::split_message_bytes(contents, start) {
Ok((this, rest)) if rest == contents.len() => Ok(this),
_ => Err(ParseError),
}
}
}
impl<'a> SplitBytes<'a> for &'a UnparsedName {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
let mut offset = 0;
while offset < 255 {
match *bytes.get(offset..).ok_or(ParseError)? {
[0, ..] => {
offset += 1;
let (bytes, rest) = bytes.split_at(offset);
return Ok((
unsafe { UnparsedName::from_bytes_unchecked(bytes) },
rest,
));
}
[l @ 1..=63, ref rest @ ..] if rest.len() >= l as usize => {
offset += 1 + l as usize;
}
[hi, _lo, ..] if hi >= 0xC0 => {
offset += 2;
let (bytes, rest) = bytes.split_at(offset);
return Ok((
unsafe { UnparsedName::from_bytes_unchecked(bytes) },
rest,
));
}
_ => return Err(ParseError),
}
}
Err(ParseError)
}
}
impl<'a> ParseBytes<'a> for &'a UnparsedName {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
match Self::split_bytes(bytes) {
Ok((this, &[])) => Ok(this),
_ => Err(ParseError),
}
}
}