hickory_proto/rr/rdata/
txt.rs1use std::fmt;
10use std::slice::Iter;
11
12#[cfg(feature = "serde-config")]
13use serde::{Deserialize, Serialize};
14
15use crate::{
16 error::ProtoResult,
17 rr::{RData, RecordData, RecordDataDecodable, RecordType},
18 serialize::binary::*,
19};
20
21#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
35#[derive(Debug, PartialEq, Eq, Hash, Clone)]
36pub struct TXT {
37 txt_data: Box<[Box<[u8]>]>,
38}
39
40impl TXT {
41 pub fn new(txt_data: Vec<String>) -> Self {
51 Self {
52 txt_data: txt_data
53 .into_iter()
54 .map(|s| s.into_bytes().into_boxed_slice())
55 .collect::<Vec<_>>()
56 .into_boxed_slice(),
57 }
58 }
59
60 pub fn from_bytes(txt_data: Vec<&[u8]>) -> Self {
71 Self {
72 txt_data: txt_data
73 .into_iter()
74 .map(|s| s.to_vec().into_boxed_slice())
75 .collect::<Vec<_>>()
76 .into_boxed_slice(),
77 }
78 }
79
80 pub fn txt_data(&self) -> &[Box<[u8]>] {
84 &self.txt_data
85 }
86
87 pub fn iter(&self) -> Iter<'_, Box<[u8]>> {
89 self.txt_data.iter()
90 }
91}
92
93impl BinEncodable for TXT {
94 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
95 for s in self.txt_data() {
96 encoder.emit_character_data(s)?;
97 }
98
99 Ok(())
100 }
101}
102
103impl RecordDataDecodable<'_> for TXT {
104 fn read_data(decoder: &mut BinDecoder<'_>, rdata_length: Restrict<u16>) -> ProtoResult<Self> {
105 let data_len = decoder.len();
106 let mut strings = Vec::with_capacity(1);
107
108 let rdata_length =
110 rdata_length.map(|u| u as usize).unverified();
111 while data_len - decoder.len() < rdata_length {
112 let string = decoder.read_character_data()?.unverified();
113 strings.push(string.to_vec().into_boxed_slice());
114 }
115 Ok(Self {
116 txt_data: strings.into_boxed_slice(),
117 })
118 }
119}
120
121impl RecordData for TXT {
122 fn try_from_rdata(data: RData) -> Result<Self, RData> {
123 match data {
124 RData::TXT(data) => Ok(data),
125 _ => Err(data),
126 }
127 }
128
129 fn try_borrow(data: &RData) -> Option<&Self> {
130 match data {
131 RData::TXT(data) => Some(data),
132 _ => None,
133 }
134 }
135
136 fn record_type(&self) -> RecordType {
137 RecordType::TXT
138 }
139
140 fn into_rdata(self) -> RData {
141 RData::TXT(self)
142 }
143}
144
145impl fmt::Display for TXT {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
169 for txt in self.txt_data.iter() {
170 f.write_str(&String::from_utf8_lossy(txt))?;
171 }
172
173 Ok(())
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 #![allow(clippy::dbg_macro, clippy::print_stdout)]
180
181 use super::*;
182
183 #[test]
184 fn test() {
185 let rdata = TXT::new(vec!["Test me some".to_string(), "more please".to_string()]);
186
187 let mut bytes = Vec::new();
188 let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
189 assert!(rdata.emit(&mut encoder).is_ok());
190 let bytes = encoder.into_bytes();
191
192 println!("bytes: {bytes:?}");
193
194 let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
195 let restrict = Restrict::new(bytes.len() as u16);
196 let read_rdata = TXT::read_data(&mut decoder, restrict).expect("Decoding error");
197 assert_eq!(rdata, read_rdata);
198 }
199
200 #[test]
201 fn publish_binary_txt_record() {
202 let bin_data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
203 let rdata = TXT::from_bytes(vec![b"Test me some", &bin_data]);
204
205 let mut bytes = Vec::new();
206 let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
207 assert!(rdata.emit(&mut encoder).is_ok());
208 let bytes = encoder.into_bytes();
209
210 println!("bytes: {bytes:?}");
211
212 let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
213 let restrict = Restrict::new(bytes.len() as u16);
214 let read_rdata = TXT::read_data(&mut decoder, restrict).expect("Decoding error");
215 assert_eq!(rdata, read_rdata);
216 }
217}