1use core::fmt::Display;
2use crate::{Buffer, DnsError, DnsMessage, DnsMessageError, MutBuffer};
3use crate::parse::ParseBytes;
4use crate::write::WriteBytes;
5
6#[derive(Copy, Clone, Debug, PartialEq)]
10pub struct Characters<'a> {
11 bytes: &'a [u8],
12}
13
14const MAX_CHARACTER_STRING_LENGTH: usize = 255;
15
16#[macro_export]
31macro_rules! dns_characters {
32 ($value:expr $(,)?) => {
33 {
34 const CHARACTERS: [u8; $value.len() + 1] = {
35 if $value.len() > u8::MAX as usize {
36 panic!("Character string too long, maximum length is 255.");
37 }
38
39 let mut result = [0; $value.len() + 1];
40 let mut index = 0;
41 loop {
42 if index == $value.len() {
43 result[0] = index as u8;
44
45 break;
46 }
47
48 result[index + 1] = $value[index];
49 index += 1;
50 }
51
52 result
53 };
54 unsafe { ::flex_dns::characters::Characters::new_unchecked(&CHARACTERS) }
55 }
56 };
57}
58
59impl<'a> Characters<'a> {
60 #[inline(always)]
68 pub const fn new(bytes: &'a [u8]) -> Result<Self, DnsMessageError> {
69 if bytes.len() > MAX_CHARACTER_STRING_LENGTH {
70 return Err(DnsMessageError::DnsError(DnsError::CharacterStringTooLong));
71 }
72
73 if bytes[0] as usize + 1 != bytes.len() {
74 return Err(DnsMessageError::DnsError(DnsError::CharacterStringInvalidLength));
75 }
76
77 Ok(Characters { bytes })
78 }
79
80 #[inline(always)]
87 pub const unsafe fn new_unchecked(bytes: &'a [u8]) -> Self {
88 Characters { bytes }
89 }
90}
91
92impl<'a> ParseBytes<'a> for Characters<'a> {
93 #[inline]
94 fn parse_bytes(bytes: &'a [u8], i: &mut usize) -> Result<Self, DnsMessageError> {
95 let length = u8::parse_bytes(bytes, i)? as usize;
96
97 if length > MAX_CHARACTER_STRING_LENGTH {
98 return Err(DnsMessageError::DnsError(DnsError::CharacterStringTooLong));
99 }
100
101 if *i + length > bytes.len() {
102 return Err(DnsMessageError::DnsError(DnsError::UnexpectedEndOfBuffer));
103 }
104
105 let bytes = &bytes[*i..*i + length];
106 *i += length;
107
108 Ok(Characters { bytes })
109 }
110}
111
112impl<'a> WriteBytes for Characters<'a> {
113 #[inline]
114 fn write<
115 const PTR_STORAGE: usize,
116 const DNS_SECTION: usize,
117 B: MutBuffer + Buffer,
118 >(
119 &self,
120 message: &mut DnsMessage<PTR_STORAGE, DNS_SECTION, B>,
121 ) -> Result<usize, DnsMessageError> {
122 let mut bytes = 0;
123
124 bytes += message.write_bytes(&[self.bytes.len() as u8])?;
125 bytes += message.write_bytes(self.bytes)?;
126
127 Ok(bytes)
128 }
129}
130
131impl<'a> AsRef<[u8]> for Characters<'a> {
132 #[inline]
133 fn as_ref(&self) -> &[u8] {
134 &self.bytes[1..] }
136}
137
138impl<'a> Display for Characters<'a> {
139 #[inline]
140 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141 for &byte in self.bytes[1..].iter() {
142 write!(f, "\\x{:02x}", byte)?;
143 }
144
145 Ok(())
146 }
147}