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