simple_dns/dns/
character_string.rs1use crate::{
2 bytes_buffer::BytesBuffer,
3 dns::WireFormat,
4 lib::{
5 fmt::{Debug, Display, Formatter},
6 Cow, String, ToString, TryFrom, Write,
7 },
8 SimpleDnsError,
9};
10
11use super::MAX_CHARACTER_STRING_LENGTH;
12
13#[derive(PartialEq, Eq, Hash, Clone)]
20pub struct CharacterString<'a> {
21 pub(crate) data: Cow<'a, [u8]>,
22}
23
24impl<'a> CharacterString<'a> {
25 pub fn new(data: &'a [u8]) -> crate::Result<Self> {
27 Self::internal_new(Cow::Borrowed(data))
28 }
29
30 fn internal_new(data: Cow<'a, [u8]>) -> crate::Result<Self> {
31 if data.len() > MAX_CHARACTER_STRING_LENGTH {
32 return Err(SimpleDnsError::InvalidCharacterString);
33 }
34 Ok(Self { data })
35 }
36
37 pub fn into_owned<'b>(self) -> CharacterString<'b> {
39 CharacterString {
40 data: self.data.into_owned().into(),
41 }
42 }
43}
44
45impl<'a> TryFrom<CharacterString<'a>> for String {
46 type Error = crate::SimpleDnsError;
47
48 fn try_from(val: CharacterString<'a>) -> Result<Self, Self::Error> {
49 match String::from_utf8(val.data.into()) {
50 Ok(s) => Ok(s),
51 Err(e) => Err(SimpleDnsError::InvalidUtf8String(e)),
52 }
53 }
54}
55
56impl<'a> WireFormat<'a> for CharacterString<'a> {
57 const MINIMUM_LEN: usize = 1;
58
59 fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
60 where
61 Self: Sized,
62 {
63 let length = data.get_u8()? as usize;
64 if length > MAX_CHARACTER_STRING_LENGTH {
65 return Err(SimpleDnsError::InvalidCharacterString);
66 }
67
68 let data = data.get_slice(length)?;
69
70 Ok(Self {
71 data: Cow::Borrowed(data),
72 })
73 }
74
75 fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
76 out.write_all(&[self.data.len() as u8])?;
77 out.write_all(&self.data)
78 }
79
80 fn len(&self) -> usize {
81 self.data.len() + Self::MINIMUM_LEN
82 }
83}
84
85impl<'a> TryFrom<&'a str> for CharacterString<'a> {
86 type Error = crate::SimpleDnsError;
87
88 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
89 CharacterString::internal_new(Cow::Borrowed(value.as_bytes()))
90 }
91}
92
93impl TryFrom<String> for CharacterString<'_> {
94 type Error = crate::SimpleDnsError;
95
96 fn try_from(value: String) -> Result<Self, Self::Error> {
97 CharacterString::internal_new(Cow::Owned(value.as_bytes().into()))
98 }
99}
100
101impl Display for CharacterString<'_> {
102 fn fmt(&self, f: &mut Formatter<'_>) -> crate::lib::fmt::Result {
103 let s = crate::lib::str::from_utf8(&self.data).unwrap();
104 f.write_str(s)
105 }
106}
107
108impl Debug for CharacterString<'_> {
109 fn fmt(&self, f: &mut Formatter<'_>) -> crate::lib::fmt::Result {
110 f.debug_struct("CharacterString")
111 .field("data", &self.to_string())
112 .finish()
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::lib::Vec;
120
121 #[test]
122 fn construct_valid_character_string() {
123 assert!(CharacterString::new(b"Iamvalid").is_ok());
124 assert!(CharacterString::new(br#""I am valid""#).is_ok());
125 assert!(CharacterString::new(br#""I am \" also valid""#).is_ok());
126 assert!(CharacterString::new(b"I am valid").is_ok());
127
128 let long_string = [0u8; 300];
129 assert!(CharacterString::new(&long_string).is_err());
130 }
131
132 #[test]
133 fn parse() {
134 let c_string = CharacterString::parse(&mut BytesBuffer::new(b"\x0esome_long_text"));
135 assert!(c_string.is_ok());
136 let c_string = c_string.unwrap();
137 assert_eq!(15, c_string.len());
138 assert_eq!("some_long_text", c_string.to_string());
139 }
140
141 #[test]
142 fn append_to_vec() {
143 let mut out = Vec::new();
144 let c_string = CharacterString::new("some_long_text".as_bytes()).unwrap();
145 c_string.write_to(&mut out).unwrap();
146
147 assert_eq!(b"\x0esome_long_text", &out[..]);
148 assert_eq!(b"\x0esome_long_text", &out[..]);
149 }
150}