flex_dns/
characters.rs

1use core::fmt::Display;
2use crate::{Buffer, DnsError, DnsMessage, DnsMessageError, MutBuffer};
3use crate::parse::ParseBytes;
4use crate::write::WriteBytes;
5
6/// A DNS message characters.
7/// It is a sequence of characters, where the first byte is the length of the
8/// sequence.
9#[derive(Copy, Clone, Debug, PartialEq)]
10pub struct Characters<'a> {
11    bytes: &'a [u8],
12}
13
14const MAX_CHARACTER_STRING_LENGTH: usize = 255;
15
16/// Create a new [`Characters`] from a byte slice. The first byte of the slice
17/// will be the length of the sequence. Only insert the characters, not the
18/// length. The maximum length of the sequence is 255. This macro accepts an
19/// expression as input, which is evaluated at compile time. If you want to
20/// create a [`Characters`] from a byte slice of unknown length, use the
21/// [`Characters::new`] function instead.
22///
23/// # Example
24/// ```
25/// use flex_dns::characters::Characters;
26/// use flex_dns::dns_characters;
27///
28/// const CHARACTERS: Characters = dns_characters!(b"Hello World!");
29/// ```
30#[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    /// Create a new [`Characters`] from a byte slice. The first byte of the
61    /// slice must be the length of the sequence. The maximum length of the
62    /// sequence is checked and 255, the first byte, must be equal to the length
63    /// of the slice minus 1, which is also checked. Use this function if you
64    /// want to create a [`Characters`] from a byte slice of unknown length.
65    /// If you know the length of the slice at compile time, use the
66    /// [`dns_characters!`] macro instead.
67    #[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    /// Create a new [`Characters`] from a byte slice. The first byte of the
81    /// slice must be the length of the sequence. The maximum length of the
82    /// sequence is not checked and 255, the first byte, must be equal to the
83    /// length of the slice minus 1, which is also not checked, hence the
84    /// `unsafe`. Using this function is unsafe cause it can lead to an invalid
85    /// DNS message.
86    #[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..] // Skip the length byte.
135    }
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}