simple_dns/dns/
character_string.rs

1use std::{borrow::Cow, convert::TryFrom, fmt::Display};
2
3use crate::{bytes_buffer::BytesBuffer, SimpleDnsError};
4
5use super::{WireFormat, MAX_CHARACTER_STRING_LENGTH};
6
7/// CharacterString is expressed in one or two ways:
8/// - as a contiguous set of characters without interior spaces,
9/// - or as a string beginning with a " and ending with a ".  
10///
11/// Inside a " delimited string any character can occur, except for a " itself,  
12/// which must be quoted using \ (back slash).
13#[derive(PartialEq, Eq, Hash, Clone)]
14pub struct CharacterString<'a> {
15    pub(crate) data: Cow<'a, [u8]>,
16}
17
18impl<'a> CharacterString<'a> {
19    /// Creates a new validated CharacterString
20    pub fn new(data: &'a [u8]) -> crate::Result<Self> {
21        Self::internal_new(Cow::Borrowed(data))
22    }
23
24    fn internal_new(data: Cow<'a, [u8]>) -> crate::Result<Self> {
25        if data.len() > MAX_CHARACTER_STRING_LENGTH {
26            return Err(SimpleDnsError::InvalidCharacterString);
27        }
28        Ok(Self { data })
29    }
30
31    /// Transforms the inner data into its owned type
32    pub fn into_owned<'b>(self) -> CharacterString<'b> {
33        CharacterString {
34            data: self.data.into_owned().into(),
35        }
36    }
37}
38
39impl<'a> TryFrom<CharacterString<'a>> for String {
40    type Error = crate::SimpleDnsError;
41
42    fn try_from(val: CharacterString<'a>) -> Result<Self, Self::Error> {
43        match String::from_utf8(val.data.into()) {
44            Ok(s) => Ok(s),
45            Err(e) => Err(SimpleDnsError::InvalidUtf8String(e)),
46        }
47    }
48}
49
50impl<'a> WireFormat<'a> for CharacterString<'a> {
51    const MINIMUM_LEN: usize = 1;
52
53    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
54    where
55        Self: Sized,
56    {
57        let length = data.get_u8()? as usize;
58        if length > MAX_CHARACTER_STRING_LENGTH {
59            return Err(SimpleDnsError::InvalidCharacterString);
60        }
61
62        let data = data.get_slice(length)?;
63
64        Ok(Self {
65            data: Cow::Borrowed(data),
66        })
67    }
68
69    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
70        out.write_all(&[self.data.len() as u8])?;
71        out.write_all(&self.data)
72            .map_err(crate::SimpleDnsError::from)
73    }
74
75    fn len(&self) -> usize {
76        self.data.len() + Self::MINIMUM_LEN
77    }
78}
79
80impl<'a> TryFrom<&'a str> for CharacterString<'a> {
81    type Error = crate::SimpleDnsError;
82
83    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
84        CharacterString::internal_new(Cow::Borrowed(value.as_bytes()))
85    }
86}
87
88impl TryFrom<String> for CharacterString<'_> {
89    type Error = crate::SimpleDnsError;
90
91    fn try_from(value: String) -> Result<Self, Self::Error> {
92        CharacterString::internal_new(Cow::Owned(value.as_bytes().into()))
93    }
94}
95
96impl Display for CharacterString<'_> {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        let s = std::str::from_utf8(&self.data).unwrap();
99        f.write_str(s)
100    }
101}
102
103impl std::fmt::Debug for CharacterString<'_> {
104    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105        f.debug_struct("CharacterString")
106            .field("data", &self.to_string())
107            .finish()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use std::{
114        collections::hash_map::DefaultHasher,
115        hash::{Hash, Hasher},
116    };
117
118    use super::*;
119
120    #[test]
121    fn construct_valid_character_string() {
122        assert!(CharacterString::new(b"Iamvalid").is_ok());
123        assert!(CharacterString::new(br#""I am valid""#).is_ok());
124        assert!(CharacterString::new(br#""I am \" also valid""#).is_ok());
125        assert!(CharacterString::new(b"I am valid").is_ok());
126
127        let long_string = [0u8; 300];
128        assert!(CharacterString::new(&long_string).is_err());
129    }
130
131    #[test]
132    fn parse() {
133        let c_string = CharacterString::parse(&mut BytesBuffer::new(b"\x0esome_long_text"));
134        assert!(c_string.is_ok());
135        let c_string = c_string.unwrap();
136        assert_eq!(15, c_string.len());
137        assert_eq!("some_long_text", c_string.to_string());
138    }
139
140    #[test]
141    fn append_to_vec() {
142        let mut out = Vec::new();
143        let c_string = CharacterString::new("some_long_text".as_bytes()).unwrap();
144        c_string.write_to(&mut out).unwrap();
145
146        assert_eq!(b"\x0esome_long_text", &out[..]);
147    }
148
149    #[test]
150    fn eq() {
151        let a = CharacterString::new(b"text").unwrap();
152        let b = CharacterString::new(b"text").unwrap();
153
154        assert_eq!(a, b);
155        assert_eq!(get_hash(a), get_hash(b));
156    }
157
158    fn get_hash(string: CharacterString) -> u64 {
159        let mut hasher = DefaultHasher::default();
160        string.hash(&mut hasher);
161        hasher.finish()
162    }
163}