use core::{
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
iter::FusedIterator,
ops::{Deref, DerefMut},
str::FromStr,
};
use crate::new::base::parse::{
ParseMessageBytes, SplitMessageBytes, split_without_compression,
};
use crate::new::base::wire::{
AsBytes, BuildBytes, ParseBytes, ParseError, SplitBytes, TruncationError,
};
use crate::new::base::{
build::{BuildInMessage, NameCompressor},
parse::parse_without_compression,
};
use crate::utils::dst::{UnsizedCopy, UnsizedCopyFrom};
#[derive(AsBytes, UnsizedCopy)]
#[repr(transparent)]
pub struct Label([u8]);
impl Label {
pub const ROOT: &'static Self = {
unsafe { Self::from_bytes_unchecked(&[0]) }
};
pub const WILDCARD: &'static Self = {
unsafe { Self::from_bytes_unchecked(&[1, b'*']) }
};
const UNESCAPED_ZONEFILE_CHARS: &[u8] = b"\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789\
!#$%&'*+,-^_`{|}~";
}
impl Label {
#[must_use]
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
unsafe { core::mem::transmute(bytes) }
}
#[must_use]
pub const unsafe fn from_mut_bytes_unchecked(
bytes: &mut [u8],
) -> &mut Self {
unsafe { core::mem::transmute(bytes) }
}
}
impl Label {
#[must_use]
pub const fn to_buf(&self) -> LabelBuf {
LabelBuf::copy_from(self)
}
#[must_use]
#[cfg(feature = "alloc")]
pub fn to_boxed(&self) -> alloc::boxed::Box<Label> {
self.unsized_copy_into()
}
pub const fn make_lowercase(&mut self) {
self.0.make_ascii_lowercase()
}
}
impl<'a> ParseMessageBytes<'a> for &'a Label {
fn parse_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<Self, ParseError> {
parse_without_compression(contents, start)
}
}
impl<'a> SplitMessageBytes<'a> for &'a Label {
fn split_message_bytes(
contents: &'a [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
split_without_compression(contents, start)
}
}
impl BuildInMessage for Label {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
_compressor: &mut NameCompressor,
) -> Result<usize, TruncationError> {
let bytes = self.as_wire();
let end = start + bytes.len();
contents
.get_mut(start..end)
.ok_or(TruncationError)?
.copy_from_slice(bytes);
Ok(end)
}
}
impl<'a> SplitBytes<'a> for &'a Label {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
let &size = bytes.first().ok_or(ParseError)?;
if size < 64 && bytes.len() > size as usize {
let (label, rest) = bytes.split_at(1 + size as usize);
Ok((unsafe { Label::from_bytes_unchecked(label) }, rest))
} else {
Err(ParseError)
}
}
}
impl<'a> ParseBytes<'a> for &'a Label {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
match Self::split_bytes(bytes) {
Ok((this, &[])) => Ok(this),
_ => Err(ParseError),
}
}
}
impl BuildBytes for Label {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
self.as_wire().build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
self.as_wire().len()
}
}
impl Label {
#[must_use]
pub const fn is_root(&self) -> bool {
self.0.len() == 1
}
#[must_use]
pub const fn is_wildcard(&self) -> bool {
matches!(self.0, [1, b'*'])
}
#[must_use]
pub const fn as_wire(&self) -> &[u8] {
&self.0
}
#[must_use]
pub const fn contents(&self) -> &[u8] {
unsafe { self.0.split_at_unchecked(1).1 }
}
#[must_use]
pub const fn contents_mut(&mut self) -> &mut [u8] {
unsafe { self.0.split_at_mut_unchecked(1).1 }
}
}
#[cfg(feature = "alloc")]
impl Clone for alloc::boxed::Box<Label> {
fn clone(&self) -> Self {
(*self).unsized_copy_into()
}
}
impl PartialEq for Label {
fn eq(&self, other: &Self) -> bool {
self.as_wire().eq_ignore_ascii_case(other.as_wire())
}
}
impl Eq for Label {}
impl PartialOrd for Label {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Label {
fn cmp(&self, other: &Self) -> Ordering {
let this = self.contents().iter().map(u8::to_ascii_lowercase);
let that = other.contents().iter().map(u8::to_ascii_lowercase);
this.cmp(that)
}
}
impl Hash for Label {
fn hash<H: Hasher>(&self, state: &mut H) {
for &byte in self.as_wire() {
state.write_u8(byte.to_ascii_lowercase())
}
}
}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.contents().iter().try_for_each(|&byte| {
if Label::UNESCAPED_ZONEFILE_CHARS.contains(&byte) {
write!(f, "{}", byte as char)
} else if byte.is_ascii_graphic() {
write!(f, "\\{}", byte as char)
} else {
write!(f, "\\{:03}", byte)
}
})
}
}
impl fmt::Debug for Label {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Label(\"{self}\")")
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Label {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer
.serialize_newtype_struct("Label", &format_args!("{self}"))
} else {
struct NV<'a>(&'a [u8]);
impl serde::Serialize for NV<'_> {
fn serialize<S>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(self.0)
}
}
serializer.serialize_newtype_struct("Label", &NV(self.contents()))
}
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct LabelBuf {
data: [u8; 64],
}
impl LabelBuf {
#[must_use]
pub const fn new() -> Self {
Self { data: [0u8; 64] }
}
#[must_use]
pub const fn copy_from(label: &Label) -> Self {
let bytes = label.as_wire();
let mut data = [0u8; 64];
let mut index = 0usize;
while index < bytes.len() {
data[index] = bytes[index];
index += 1;
}
Self { data }
}
}
impl Default for LabelBuf {
fn default() -> Self {
Self::new()
}
}
impl UnsizedCopyFrom for LabelBuf {
type Source = Label;
fn unsized_copy_from(value: &Self::Source) -> Self {
Self::copy_from(value)
}
}
impl LabelBuf {
pub const fn append(
&mut self,
bytes: &[u8],
) -> Result<(), TruncationError> {
let len = self.data[0] as usize;
let new_len = len + bytes.len();
if new_len >= 64 {
return Err(TruncationError);
}
let target = unsafe {
self.data
.split_at_mut_unchecked(1 + len)
.1
.split_at_mut_unchecked(bytes.len())
.0
};
target.copy_from_slice(bytes);
self.data[0] = new_len as u8;
Ok(())
}
pub const fn push(&mut self, byte: u8) -> Result<(), TruncationError> {
let len = self.data[0] as usize;
if len >= 63 {
return Err(TruncationError);
}
self.data[1 + len] = byte;
self.data[0] = 1 + len as u8;
Ok(())
}
pub const fn truncate(&mut self, new_len: usize) {
let len = self.data[0] as usize;
assert!(new_len <= len, "Label is shorter than desired length");
self.data[0] = new_len as u8;
}
}
impl ParseMessageBytes<'_> for LabelBuf {
fn parse_message_bytes(
contents: &'_ [u8],
start: usize,
) -> Result<Self, ParseError> {
parse_without_compression(contents, start)
}
}
impl SplitMessageBytes<'_> for LabelBuf {
fn split_message_bytes(
contents: &'_ [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
split_without_compression(contents, start)
}
}
impl BuildInMessage for LabelBuf {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
compressor: &mut NameCompressor,
) -> Result<usize, TruncationError> {
Label::build_in_message(self, contents, start, compressor)
}
}
impl ParseBytes<'_> for LabelBuf {
fn parse_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
<&Label>::parse_bytes(bytes).map(Self::copy_from)
}
}
impl SplitBytes<'_> for LabelBuf {
fn split_bytes(bytes: &'_ [u8]) -> Result<(Self, &'_ [u8]), ParseError> {
<&Label>::split_bytes(bytes)
.map(|(label, rest)| (Self::copy_from(label), rest))
}
}
impl BuildBytes for LabelBuf {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
(**self).build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
(**self).built_bytes_size()
}
}
impl LabelBuf {
#[must_use]
pub const fn as_label(&self) -> &Label {
let size = self.data[0];
let label = unsafe {
core::slice::from_raw_parts(self.data.as_ptr(), 1 + size as usize)
};
unsafe { Label::from_bytes_unchecked(label) }
}
#[must_use]
pub const fn as_mut_label(&mut self) -> &mut Label {
let size = self.data[0];
let label = unsafe {
core::slice::from_raw_parts_mut(
self.data.as_mut_ptr(),
1 + size as usize,
)
};
unsafe { Label::from_mut_bytes_unchecked(label) }
}
}
impl Deref for LabelBuf {
type Target = Label;
fn deref(&self) -> &Self::Target {
self.as_label()
}
}
impl DerefMut for LabelBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_label()
}
}
impl Borrow<Label> for LabelBuf {
fn borrow(&self) -> &Label {
self
}
}
impl BorrowMut<Label> for LabelBuf {
fn borrow_mut(&mut self) -> &mut Label {
self
}
}
impl AsRef<Label> for LabelBuf {
fn as_ref(&self) -> &Label {
self
}
}
impl AsMut<Label> for LabelBuf {
fn as_mut(&mut self) -> &mut Label {
self
}
}
impl PartialEq for LabelBuf {
fn eq(&self, that: &Self) -> bool {
**self == **that
}
}
impl Eq for LabelBuf {}
impl PartialOrd for LabelBuf {
fn partial_cmp(&self, that: &Self) -> Option<Ordering> {
Some(self.cmp(that))
}
}
impl Ord for LabelBuf {
fn cmp(&self, that: &Self) -> Ordering {
(**self).cmp(&**that)
}
}
impl Hash for LabelBuf {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state)
}
}
impl fmt::Display for LabelBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl fmt::Debug for LabelBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LabelBuf(\"{self}\")")
}
}
impl LabelBuf {
pub fn parse_str(mut s: &[u8]) -> Result<Self, LabelParseError> {
let mut this = Self::new();
loop {
let &[b, ref rest @ ..] = s else {
return Ok(this);
};
s = rest;
if Label::UNESCAPED_ZONEFILE_CHARS.contains(&b) {
this.push(b).map_err(|_| LabelParseError::Overlong)?;
} else if b == b'\\' {
let &[b, ref rest @ ..] = s else {
return Err(LabelParseError::PartialEscape);
};
let value = if b.is_ascii_digit() {
let (digits, rest) = s
.split_at_checked(3)
.ok_or(LabelParseError::PartialEscape)?;
s = rest;
let digits = core::str::from_utf8(digits)
.map_err(|_| LabelParseError::InvalidEscape)?;
digits
.parse()
.map_err(|_| LabelParseError::InvalidEscape)?
} else if b.is_ascii_graphic() {
s = rest;
b
} else {
return Err(LabelParseError::InvalidEscape);
};
this.push(value).map_err(|_| LabelParseError::Overlong)?;
} else {
return Err(LabelParseError::InvalidChar);
};
}
}
pub fn split_str(mut s: &[u8]) -> Result<(Self, &[u8]), LabelSplitError> {
let mut this = Self::new();
loop {
let full = s;
let &[b, ref rest @ ..] = s else {
return Err(LabelSplitError::ShortInput);
};
s = rest;
if Label::UNESCAPED_ZONEFILE_CHARS.contains(&b) {
this.push(b).map_err(|_| LabelSplitError::Overlong)?;
} else if b == b'\\' {
let &[b, ref rest @ ..] = s else {
return Err(LabelSplitError::ShortInput);
};
let value = if b.is_ascii_digit() {
let (digits, rest) = s
.split_at_checked(3)
.ok_or(LabelSplitError::ShortInput)?;
s = rest;
let digits = core::str::from_utf8(digits)
.map_err(|_| LabelSplitError::InvalidEscape)?;
digits
.parse()
.map_err(|_| LabelSplitError::InvalidEscape)?
} else if b.is_ascii_graphic() {
s = rest;
b
} else {
return Err(LabelSplitError::InvalidEscape);
};
this.push(value).map_err(|_| LabelSplitError::Overlong)?;
} else {
break Ok((this, full));
};
}
}
}
impl FromStr for LabelBuf {
type Err = LabelParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse_str(s.as_bytes())
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for LabelBuf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(**self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'a> serde::Deserialize<'a> for LabelBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
if deserializer.is_human_readable() {
struct V;
impl serde::de::Visitor<'_> for V {
type Value = LabelBuf;
fn expecting(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.write_str("a label, in the DNS zonefile format")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_err(|err| E::custom(err))
}
}
struct NV;
impl<'a> serde::de::Visitor<'a> for NV {
type Value = LabelBuf;
fn expecting(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.write_str("a DNS label")
}
fn visit_newtype_struct<D>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'a>,
{
deserializer.deserialize_str(V)
}
}
deserializer.deserialize_newtype_struct("Label", NV)
} else {
struct V;
impl serde::de::Visitor<'_> for V {
type Value = LabelBuf;
fn expecting(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.write_str("the contents of a DNS label")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let mut buf = LabelBuf::new();
buf.append(v).map_err(|_| {
E::custom(
"misformatted label for the DNS wire format",
)
})?;
Ok(buf)
}
}
struct NV;
impl<'a> serde::de::Visitor<'a> for NV {
type Value = LabelBuf;
fn expecting(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.write_str("a DNS label")
}
fn visit_newtype_struct<D>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'a>,
{
deserializer.deserialize_bytes(V)
}
}
deserializer.deserialize_newtype_struct("Label", NV)
}
}
}
#[cfg(all(feature = "serde", feature = "alloc"))]
impl<'a> serde::Deserialize<'a> for alloc::boxed::Box<Label> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
LabelBuf::deserialize(deserializer)
.map(|this| this.unsized_copy_into())
}
}
#[derive(Clone)]
pub struct LabelIter<'a> {
bytes: &'a [u8],
}
impl<'a> LabelIter<'a> {
pub const unsafe fn new_unchecked(bytes: &'a [u8]) -> Self {
Self { bytes }
}
}
impl<'a> LabelIter<'a> {
pub const fn remaining(&self) -> &'a [u8] {
self.bytes
}
pub const fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl<'a> Iterator for LabelIter<'a> {
type Item = &'a Label;
fn next(&mut self) -> Option<Self::Item> {
if self.bytes.is_empty() {
return None;
}
let (head, tail) =
unsafe { <&Label>::split_bytes(self.bytes).unwrap_unchecked() };
self.bytes = tail;
Some(head)
}
}
impl FusedIterator for LabelIter<'_> {}
impl fmt::Debug for LabelIter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Labels<'a>(&'a LabelIter<'a>);
impl fmt::Debug for Labels<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.clone()).finish()
}
}
f.debug_tuple("LabelIter").field(&Labels(self)).finish()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! new_base_name_label {
($value:literal) => {
const {
const BUFFER: &$crate::new::base::name::LabelBuf =
&$crate::new::base::name::label_buf!($value);
BUFFER.as_label()
}
};
}
pub use crate::new_base_name_label as label;
#[doc(hidden)]
#[macro_export]
macro_rules! new_base_name_label_buf {
($value:literal) => {
const {
let mut buffer = $crate::new::base::name::LabelBuf::new();
assert!(buffer.append($value).is_ok());
buffer
}
};
}
pub use crate::new_base_name_label_buf as label_buf;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LabelParseError {
Overlong,
InvalidChar,
PartialEscape,
InvalidEscape,
}
impl core::error::Error for LabelParseError {}
impl fmt::Display for LabelParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Overlong => "the label was too large",
Self::InvalidChar => "the label contained an invalid character",
Self::PartialEscape => "the label contained an incomplete escape",
Self::InvalidEscape => "the label contained an invalid escape",
})
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LabelSplitError {
Overlong,
InvalidChar,
InvalidEscape,
ShortInput,
}
impl core::error::Error for LabelSplitError {}
impl fmt::Display for LabelSplitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Overlong => "the label was too large",
Self::InvalidChar => "the label contained an invalid character",
Self::InvalidEscape => "the label contained an invalid escape",
Self::ShortInput => "the input was too short to parse the label",
})
}
}
#[cfg(test)]
mod tests {
use super::Label;
use crate::new::base::wire::{ParseBytes, ParseError, SplitBytes};
#[test]
fn parsing() {
let good = [
b"\x00abc" as &[u8],
b"\x07example\x03org\x00",
b"\x07f\x00\x00&\x8Fbar-foo",
b"\x3Fthis is a label of the longest valid length and it's surprising(ly big)",
];
for input in good {
let expected_len = input[0] as usize + 1;
assert_eq!(<&Label>::parse_bytes(input), Err(ParseError));
let (actual, rest) = <&Label>::split_bytes(input).unwrap();
assert_eq!(actual.as_wire().len(), expected_len);
assert_eq!(actual.as_wire().as_ptr(), input.as_ptr());
assert_eq!(actual.as_wire().len() + rest.len(), input.len());
assert_eq!(
rest.as_ptr(),
input.as_ptr().wrapping_add(expected_len)
);
let min_input = &input[..expected_len];
let (actual, rest) = <&Label>::split_bytes(min_input).unwrap();
assert_eq!(actual.as_wire().as_ptr(), min_input.as_ptr());
assert_eq!(actual.as_wire().len(), min_input.len());
assert_eq!(rest, &[] as &[u8]);
let actual = <&Label>::parse_bytes(min_input).unwrap();
assert_eq!(actual.as_wire().as_ptr(), min_input.as_ptr());
assert_eq!(actual.as_wire().len(), min_input.len());
let short_input = &input[..expected_len - 1];
assert_eq!(<&Label>::split_bytes(short_input), Err(ParseError));
assert_eq!(<&Label>::parse_bytes(short_input), Err(ParseError));
}
let bad = [
b"\x40this is not a valid label but it would be if 64 was a valid label length" as &[u8],
];
for input in bad {
assert_eq!(<&Label>::split_bytes(input), Err(ParseError));
assert_eq!(<&Label>::parse_bytes(input), Err(ParseError));
}
}
}