use core::fmt::Display;
use crate::{Buffer, DnsError, DnsMessage, DnsMessageError, MutBuffer};
use crate::parse::ParseBytes;
use crate::write::WriteBytes;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Characters<'a> {
bytes: &'a [u8],
}
const MAX_CHARACTER_STRING_LENGTH: usize = 255;
#[macro_export]
macro_rules! dns_characters {
($value:expr $(,)?) => {
{
const CHARACTERS: [u8; $value.len() + 1] = {
if $value.len() > u8::MAX as usize {
panic!("Character string too long, maximum length is 255.");
}
let mut result = [0; $value.len() + 1];
let mut index = 0;
loop {
if index == $value.len() {
result[0] = index as u8;
break;
}
result[index + 1] = $value[index];
index += 1;
}
result
};
unsafe { ::flex_dns::characters::Characters::new_unchecked(&CHARACTERS) }
}
};
}
impl<'a> Characters<'a> {
#[inline(always)]
pub const fn new(bytes: &'a [u8]) -> Result<Self, DnsMessageError> {
if bytes.len() > MAX_CHARACTER_STRING_LENGTH {
return Err(DnsMessageError::DnsError(DnsError::CharacterStringTooLong));
}
if bytes[0] as usize + 1 != bytes.len() {
return Err(DnsMessageError::DnsError(DnsError::CharacterStringInvalidLength));
}
Ok(Characters { bytes })
}
#[inline(always)]
pub const unsafe fn new_unchecked(bytes: &'a [u8]) -> Self {
Characters { bytes }
}
}
impl<'a> ParseBytes<'a> for Characters<'a> {
#[inline]
fn parse_bytes(bytes: &'a [u8], i: &mut usize) -> Result<Self, DnsMessageError> {
let length = u8::parse_bytes(bytes, i)? as usize;
if length > MAX_CHARACTER_STRING_LENGTH {
return Err(DnsMessageError::DnsError(DnsError::CharacterStringTooLong));
}
if *i + length > bytes.len() {
return Err(DnsMessageError::DnsError(DnsError::UnexpectedEndOfBuffer));
}
let bytes = &bytes[*i..*i + length];
*i += length;
Ok(Characters { bytes })
}
}
impl<'a> WriteBytes for Characters<'a> {
#[inline]
fn write<
const PTR_STORAGE: usize,
const DNS_SECTION: usize,
B: MutBuffer + Buffer,
>(
&self,
message: &mut DnsMessage<PTR_STORAGE, DNS_SECTION, B>,
) -> Result<usize, DnsMessageError> {
let mut bytes = 0;
bytes += message.write_bytes(&[self.bytes.len() as u8])?;
bytes += message.write_bytes(self.bytes)?;
Ok(bytes)
}
}
impl<'a> AsRef<[u8]> for Characters<'a> {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.bytes[1..] }
}
impl<'a> Display for Characters<'a> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for &byte in self.bytes[1..].iter() {
write!(f, "\\x{:02x}", byte)?;
}
Ok(())
}
}