1use super::cmp::CanonicalOrd;
26use super::iana::Rtype;
27use super::scan::{Scan, Scanner, ScannerError, Symbol};
28use super::wire::{Compose, Composer, ParseError};
29use crate::utils::base16;
30use core::cmp::Ordering;
31use core::fmt;
32use octseq::octets::{Octets, OctetsFrom};
33use octseq::parse::Parser;
34
35pub trait RecordData {
42 fn rtype(&self) -> Rtype;
47}
48
49impl<'a, T: RecordData> RecordData for &'a T {
50 fn rtype(&self) -> Rtype {
51 (*self).rtype()
52 }
53}
54
55pub trait ComposeRecordData: RecordData {
59 fn rdlen(&self, compress: bool) -> Option<u16>;
69
70 fn compose_rdata<Target: Composer + ?Sized>(
72 &self,
73 target: &mut Target,
74 ) -> Result<(), Target::AppendError>;
75
76 fn compose_canonical_rdata<Target: Composer + ?Sized>(
78 &self,
79 target: &mut Target,
80 ) -> Result<(), Target::AppendError>;
81
82 fn compose_len_rdata<Target: Composer + ?Sized>(
84 &self,
85 target: &mut Target,
86 ) -> Result<(), Target::AppendError> {
87 if let Some(rdlen) = self.rdlen(target.can_compress()) {
88 rdlen.compose(target)?;
89 self.compose_rdata(target)
90 } else {
91 compose_prefixed(target, |target| self.compose_rdata(target))
92 }
93 }
94
95 fn compose_canonical_len_rdata<Target: Composer + ?Sized>(
97 &self,
98 target: &mut Target,
99 ) -> Result<(), Target::AppendError> {
100 if let Some(rdlen) = self.rdlen(false) {
101 rdlen.compose(target)?;
102 self.compose_canonical_rdata(target)
103 } else {
104 compose_prefixed(target, |target| {
105 self.compose_canonical_rdata(target)
106 })
107 }
108 }
109}
110
111fn compose_prefixed<Target: Composer + ?Sized, F>(
112 target: &mut Target,
113 op: F,
114) -> Result<(), Target::AppendError>
115where
116 F: FnOnce(&mut Target) -> Result<(), Target::AppendError>,
117{
118 target.append_slice(&[0; 2])?;
119 let pos = target.as_ref().len();
120 match op(target) {
121 Ok(_) => {
122 let len = u16::try_from(target.as_ref().len() - pos)
123 .expect("long data");
124 target.as_mut()[pos - 2..pos]
125 .copy_from_slice(&(len).to_be_bytes());
126 Ok(())
127 }
128 Err(err) => {
129 target.truncate(pos);
130 Err(err)
131 }
132 }
133}
134
135impl<'a, T: ComposeRecordData> ComposeRecordData for &'a T {
136 fn rdlen(&self, compress: bool) -> Option<u16> {
137 (*self).rdlen(compress)
138 }
139
140 fn compose_rdata<Target: Composer + ?Sized>(
141 &self,
142 target: &mut Target,
143 ) -> Result<(), Target::AppendError> {
144 (*self).compose_rdata(target)
145 }
146
147 fn compose_canonical_rdata<Target: Composer + ?Sized>(
148 &self,
149 target: &mut Target,
150 ) -> Result<(), Target::AppendError> {
151 (*self).compose_canonical_rdata(target)
152 }
153}
154
155pub trait ParseRecordData<'a, Octs: ?Sized>: RecordData + Sized {
165 fn parse_rdata(
179 rtype: Rtype,
180 parser: &mut Parser<'a, Octs>,
181 ) -> Result<Option<Self>, ParseError>;
182}
183
184#[derive(Clone)]
211#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
212pub struct UnknownRecordData<Octs> {
213 rtype: Rtype,
215
216 #[cfg_attr(
218 feature = "serde",
219 serde(
220 serialize_with = "crate::utils::base16::serde::serialize",
221 deserialize_with = "crate::utils::base16::serde::deserialize",
222 bound(
223 serialize = "Octs: AsRef<[u8]> + octseq::serde::SerializeOctets",
224 deserialize = "\
225 Octs: \
226 octseq::builder::FromBuilder + \
227 octseq::serde::DeserializeOctets<'de>, \
228 <Octs as octseq::builder::FromBuilder>::Builder: \
229 octseq::builder::EmptyBuilder, \
230 ",
231 )
232 )
233 )]
234 data: Octs,
235}
236
237impl<Octs> UnknownRecordData<Octs> {
238 pub fn from_octets(
240 rtype: Rtype,
241 data: Octs,
242 ) -> Result<Self, LongRecordData>
243 where
244 Octs: AsRef<[u8]>,
245 {
246 LongRecordData::check_len(data.as_ref().len())?;
247 Ok(UnknownRecordData { rtype, data })
248 }
249
250 pub fn rtype(&self) -> Rtype {
252 self.rtype
253 }
254
255 pub fn data(&self) -> &Octs {
257 &self.data
258 }
259
260 pub fn scan<S: Scanner<Octets = Octs>>(
264 rtype: Rtype,
265 scanner: &mut S,
266 ) -> Result<Self, S::Error>
267 where
268 Octs: AsRef<[u8]>,
269 {
270 let mut first = true;
272 scanner.scan_symbols(|symbol| {
273 if first {
274 first = false;
275 match symbol {
276 Symbol::SimpleEscape(b'#') => Ok(()),
277 _ => Err(S::Error::custom("'\\#' expected")),
278 }
279 } else {
280 Err(S::Error::custom("'\\#' expected"))
281 }
282 })?;
283 Self::scan_without_marker(rtype, scanner)
284 }
285
286 pub fn scan_without_marker<S: Scanner<Octets = Octs>>(
288 rtype: Rtype,
289 scanner: &mut S,
290 ) -> Result<Self, S::Error>
291 where
292 Octs: AsRef<[u8]>,
293 {
294 let len = u16::scan(scanner)?;
296
297 let data = scanner.convert_entry(base16::SymbolConverter::new())?;
299
300 if data.as_ref().len() != usize::from(len) {
301 return Err(S::Error::custom(
302 "generic data has incorrect length",
303 ));
304 }
305
306 Ok(UnknownRecordData { rtype, data })
307 }
308}
309
310impl<Octs, SrcOcts> OctetsFrom<UnknownRecordData<SrcOcts>>
313 for UnknownRecordData<Octs>
314where
315 Octs: OctetsFrom<SrcOcts>,
316{
317 type Error = Octs::Error;
318
319 fn try_octets_from(
320 source: UnknownRecordData<SrcOcts>,
321 ) -> Result<Self, Self::Error> {
322 Ok(UnknownRecordData {
323 rtype: source.rtype,
324 data: Octs::try_octets_from(source.data)?,
325 })
326 }
327}
328
329impl<Octs, Other> PartialEq<UnknownRecordData<Other>>
332 for UnknownRecordData<Octs>
333where
334 Octs: AsRef<[u8]>,
335 Other: AsRef<[u8]>,
336{
337 fn eq(&self, other: &UnknownRecordData<Other>) -> bool {
338 self.data.as_ref().eq(other.data.as_ref())
339 }
340}
341
342impl<Octs: AsRef<[u8]>> Eq for UnknownRecordData<Octs> {}
343
344impl<Octs, Other> PartialOrd<UnknownRecordData<Other>>
347 for UnknownRecordData<Octs>
348where
349 Octs: AsRef<[u8]>,
350 Other: AsRef<[u8]>,
351{
352 fn partial_cmp(
353 &self,
354 other: &UnknownRecordData<Other>,
355 ) -> Option<Ordering> {
356 self.data.as_ref().partial_cmp(other.data.as_ref())
357 }
358}
359
360impl<Octs, Other> CanonicalOrd<UnknownRecordData<Other>>
361 for UnknownRecordData<Octs>
362where
363 Octs: AsRef<[u8]>,
364 Other: AsRef<[u8]>,
365{
366 fn canonical_cmp(&self, other: &UnknownRecordData<Other>) -> Ordering {
367 self.data.as_ref().cmp(other.data.as_ref())
368 }
369}
370
371impl<Octs: AsRef<[u8]>> Ord for UnknownRecordData<Octs> {
372 fn cmp(&self, other: &Self) -> Ordering {
373 self.data.as_ref().cmp(other.data.as_ref())
374 }
375}
376
377impl<Octs: AsRef<[u8]>> ComposeRecordData for UnknownRecordData<Octs> {
380 fn rdlen(&self, _compress: bool) -> Option<u16> {
381 Some(u16::try_from(self.data.as_ref().len()).expect("long rdata"))
382 }
383
384 fn compose_rdata<Target: Composer + ?Sized>(
385 &self,
386 target: &mut Target,
387 ) -> Result<(), Target::AppendError> {
388 target.append_slice(self.data.as_ref())
389 }
390
391 fn compose_canonical_rdata<Target: Composer + ?Sized>(
392 &self,
393 target: &mut Target,
394 ) -> Result<(), Target::AppendError> {
395 self.compose_rdata(target)
396 }
397}
398
399impl<Octs: AsRef<[u8]>> RecordData for UnknownRecordData<Octs> {
402 fn rtype(&self) -> Rtype {
403 self.rtype
404 }
405}
406
407impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
408 for UnknownRecordData<Octs::Range<'a>>
409{
410 fn parse_rdata(
411 rtype: Rtype,
412 parser: &mut Parser<'a, Octs>,
413 ) -> Result<Option<Self>, ParseError> {
414 let rdlen = parser.remaining();
415 parser
416 .parse_octets(rdlen)
417 .map(|data| Some(Self { rtype, data }))
418 .map_err(Into::into)
419 }
420}
421
422impl<Octs: AsRef<[u8]>> fmt::Display for UnknownRecordData<Octs> {
425 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426 write!(f, "\\# {}", self.data.as_ref().len())?;
427 for ch in self.data.as_ref() {
428 write!(f, " {:02x}", *ch)?
429 }
430 Ok(())
431 }
432}
433
434impl<Octs: AsRef<[u8]>> fmt::Debug for UnknownRecordData<Octs> {
437 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
438 f.write_str("UnknownRecordData(")?;
439 fmt::Display::fmt(self, f)?;
440 f.write_str(")")
441 }
442}
443
444#[derive(Clone, Copy, Debug)]
448pub struct LongRecordData();
449
450impl LongRecordData {
451 #[must_use]
452 pub fn as_str(self) -> &'static str {
453 "record data too long"
454 }
455
456 pub fn check_len(len: usize) -> Result<(), Self> {
457 if len > usize::from(u16::MAX) {
458 Err(LongRecordData())
459 } else {
460 Ok(())
461 }
462 }
463}
464
465impl fmt::Display for LongRecordData {
466 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467 f.write_str(self.as_str())
468 }
469}
470
471#[cfg(feature = "std")]
472impl std::error::Error for LongRecordData {}
473
474#[cfg(test)]
477#[cfg(all(feature = "std", feature = "bytes"))]
478pub(crate) mod test {
479 use super::super::scan::{IterScanner, Scanner};
480 use super::super::wire::ParseError;
481 use super::*;
482 use bytes::{Bytes, BytesMut};
483 use core::fmt::Debug;
484 use octseq::builder::infallible;
485 use std::vec::Vec;
486
487 pub fn test_rdlen<R: ComposeRecordData>(data: R) {
496 let mut buf = Vec::new();
497 infallible(data.compose_rdata(&mut buf));
498 assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
499 buf.clear();
500 infallible(data.compose_canonical_rdata(&mut buf));
501 assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
502 }
503
504 pub fn test_compose_parse<In, F, Out>(data: &In, parse: F)
506 where
507 In: ComposeRecordData + PartialEq<Out> + Debug,
508 F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
509 Out: Debug,
510 {
511 let mut buf = BytesMut::new();
512 infallible(data.compose_rdata(&mut buf));
513 let buf = buf.freeze();
514 let mut parser = Parser::from_ref(&buf);
515 let parsed = (parse)(&mut parser).unwrap();
516 assert_eq!(parser.remaining(), 0);
517 assert_eq!(*data, parsed);
518 }
519
520 type TestScanner =
521 IterScanner<std::vec::IntoIter<std::string::String>, Vec<u8>>;
522
523 pub fn test_scan<F, T, X>(input: &[&str], scan: F, expected: &X)
525 where
526 F: FnOnce(
527 &mut TestScanner,
528 ) -> Result<T, <TestScanner as Scanner>::Error>,
529 T: Debug,
530 X: Debug + PartialEq<T>,
531 {
532 let mut scanner = IterScanner::new(
533 input
534 .iter()
535 .map(|s| std::string::String::from(*s))
536 .collect::<Vec<_>>(),
537 );
538 assert_eq!(*expected, scan(&mut scanner).unwrap(),);
539 assert!(scanner.is_exhausted());
540 }
541}