1use super::cmp::CanonicalOrd;
19use super::iana::Rtype;
20use super::scan::{Scan, Scanner, ScannerError, Symbol};
21use super::wire::{Compose, Composer, ParseError};
22use super::zonefile_fmt::{self, Formatter, ZonefileFmt};
23use crate::utils::base16;
24use core::cmp::Ordering;
25use core::fmt;
26use octseq::octets::{Octets, OctetsFrom};
27use octseq::parse::Parser;
28
29pub trait RecordData {
36 fn rtype(&self) -> Rtype;
41}
42
43impl<T: RecordData> RecordData for &T {
44 fn rtype(&self) -> Rtype {
45 (*self).rtype()
46 }
47}
48
49pub trait ComposeRecordData: RecordData {
53 fn rdlen(&self, compress: bool) -> Option<u16>;
63
64 fn compose_rdata<Target: Composer + ?Sized>(
66 &self,
67 target: &mut Target,
68 ) -> Result<(), Target::AppendError>;
69
70 fn compose_canonical_rdata<Target: Composer + ?Sized>(
72 &self,
73 target: &mut Target,
74 ) -> Result<(), Target::AppendError>;
75
76 fn compose_len_rdata<Target: Composer + ?Sized>(
78 &self,
79 target: &mut Target,
80 ) -> Result<(), Target::AppendError> {
81 if let Some(rdlen) = self.rdlen(target.can_compress()) {
82 rdlen.compose(target)?;
83 self.compose_rdata(target)
84 } else {
85 compose_prefixed(target, |target| self.compose_rdata(target))
86 }
87 }
88
89 fn compose_canonical_len_rdata<Target: Composer + ?Sized>(
91 &self,
92 target: &mut Target,
93 ) -> Result<(), Target::AppendError> {
94 if let Some(rdlen) = self.rdlen(false) {
95 rdlen.compose(target)?;
96 self.compose_canonical_rdata(target)
97 } else {
98 compose_prefixed(target, |target| {
99 self.compose_canonical_rdata(target)
100 })
101 }
102 }
103}
104
105fn compose_prefixed<Target: Composer + ?Sized, F>(
106 target: &mut Target,
107 op: F,
108) -> Result<(), Target::AppendError>
109where
110 F: FnOnce(&mut Target) -> Result<(), Target::AppendError>,
111{
112 target.append_slice(&[0; 2])?;
113 let pos = target.as_ref().len();
114 match op(target) {
115 Ok(_) => {
116 let len = u16::try_from(target.as_ref().len() - pos)
117 .expect("long data");
118 target.as_mut()[pos - 2..pos]
119 .copy_from_slice(&(len).to_be_bytes());
120 Ok(())
121 }
122 Err(err) => {
123 target.truncate(pos);
124 Err(err)
125 }
126 }
127}
128
129impl<T: ComposeRecordData> ComposeRecordData for &T {
130 fn rdlen(&self, compress: bool) -> Option<u16> {
131 (*self).rdlen(compress)
132 }
133
134 fn compose_rdata<Target: Composer + ?Sized>(
135 &self,
136 target: &mut Target,
137 ) -> Result<(), Target::AppendError> {
138 (*self).compose_rdata(target)
139 }
140
141 fn compose_canonical_rdata<Target: Composer + ?Sized>(
142 &self,
143 target: &mut Target,
144 ) -> Result<(), Target::AppendError> {
145 (*self).compose_canonical_rdata(target)
146 }
147}
148
149pub trait ParseRecordData<'a, Octs: ?Sized>: RecordData + Sized {
157 fn parse_rdata(
171 rtype: Rtype,
172 parser: &mut Parser<'a, Octs>,
173 ) -> Result<Option<Self>, ParseError>;
174}
175
176pub trait ParseAnyRecordData<'a, Octs: ?Sized>: RecordData + Sized {
188 fn parse_any_rdata(
197 rtype: Rtype,
198 parser: &mut Parser<'a, Octs>,
199 ) -> Result<Self, ParseError>;
200}
201
202#[derive(Clone)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub struct UnknownRecordData<Octs> {
231 rtype: Rtype,
233
234 #[cfg_attr(
236 feature = "serde",
237 serde(
238 serialize_with = "crate::utils::base16::serde::serialize",
239 deserialize_with = "crate::utils::base16::serde::deserialize",
240 bound(
241 serialize = "Octs: AsRef<[u8]> + octseq::serde::SerializeOctets",
242 deserialize = "\
243 Octs: \
244 octseq::builder::FromBuilder + \
245 octseq::serde::DeserializeOctets<'de>, \
246 <Octs as octseq::builder::FromBuilder>::Builder: \
247 octseq::builder::EmptyBuilder, \
248 ",
249 )
250 )
251 )]
252 data: Octs,
253}
254
255impl<Octs> UnknownRecordData<Octs> {
256 pub fn from_octets(
258 rtype: Rtype,
259 data: Octs,
260 ) -> Result<Self, LongRecordData>
261 where
262 Octs: AsRef<[u8]>,
263 {
264 LongRecordData::check_len(data.as_ref().len())?;
265 Ok(UnknownRecordData { rtype, data })
266 }
267
268 pub fn rtype(&self) -> Rtype {
270 self.rtype
271 }
272
273 pub fn data(&self) -> &Octs {
275 &self.data
276 }
277
278 pub fn scan<S: Scanner<Octets = Octs>>(
282 rtype: Rtype,
283 scanner: &mut S,
284 ) -> Result<Self, S::Error>
285 where
286 Octs: AsRef<[u8]>,
287 {
288 let mut first = true;
290 scanner.scan_symbols(|symbol| {
291 if first {
292 first = false;
293 match symbol {
294 Symbol::SimpleEscape(b'#') => Ok(()),
295 _ => Err(S::Error::custom("'\\#' expected")),
296 }
297 } else {
298 Err(S::Error::custom("'\\#' expected"))
299 }
300 })?;
301 Self::scan_without_marker(rtype, scanner)
302 }
303
304 pub fn scan_without_marker<S: Scanner<Octets = Octs>>(
306 rtype: Rtype,
307 scanner: &mut S,
308 ) -> Result<Self, S::Error>
309 where
310 Octs: AsRef<[u8]>,
311 {
312 let len = u16::scan(scanner)?;
314
315 let data = scanner.convert_entry(base16::SymbolConverter::new())?;
317
318 if data.as_ref().len() != usize::from(len) {
319 return Err(S::Error::custom(
320 "generic data has incorrect length",
321 ));
322 }
323
324 Ok(UnknownRecordData { rtype, data })
325 }
326
327 pub fn parse_any_rdata<'a, SrcOcts>(
333 rtype: Rtype,
334 parser: &mut Parser<'a, SrcOcts>,
335 ) -> Result<Self, ParseError>
336 where
337 SrcOcts: Octets<Range<'a> = Octs> + ?Sized + 'a,
338 {
339 let rdlen = parser.remaining();
340 parser
341 .parse_octets(rdlen)
342 .map(|data| Self { rtype, data })
343 .map_err(Into::into)
344 }
345}
346
347impl<Octs, SrcOcts> OctetsFrom<UnknownRecordData<SrcOcts>>
350 for UnknownRecordData<Octs>
351where
352 Octs: OctetsFrom<SrcOcts>,
353{
354 type Error = Octs::Error;
355
356 fn try_octets_from(
357 source: UnknownRecordData<SrcOcts>,
358 ) -> Result<Self, Self::Error> {
359 Ok(UnknownRecordData {
360 rtype: source.rtype,
361 data: Octs::try_octets_from(source.data)?,
362 })
363 }
364}
365
366impl<Octs, Other> PartialEq<UnknownRecordData<Other>>
369 for UnknownRecordData<Octs>
370where
371 Octs: AsRef<[u8]>,
372 Other: AsRef<[u8]>,
373{
374 fn eq(&self, other: &UnknownRecordData<Other>) -> bool {
375 self.data.as_ref().eq(other.data.as_ref())
376 }
377}
378
379impl<Octs: AsRef<[u8]>> Eq for UnknownRecordData<Octs> {}
380
381impl<Octs, Other> PartialOrd<UnknownRecordData<Other>>
384 for UnknownRecordData<Octs>
385where
386 Octs: AsRef<[u8]>,
387 Other: AsRef<[u8]>,
388{
389 fn partial_cmp(
390 &self,
391 other: &UnknownRecordData<Other>,
392 ) -> Option<Ordering> {
393 self.data.as_ref().partial_cmp(other.data.as_ref())
394 }
395}
396
397impl<Octs, Other> CanonicalOrd<UnknownRecordData<Other>>
398 for UnknownRecordData<Octs>
399where
400 Octs: AsRef<[u8]>,
401 Other: AsRef<[u8]>,
402{
403 fn canonical_cmp(&self, other: &UnknownRecordData<Other>) -> Ordering {
404 self.data.as_ref().cmp(other.data.as_ref())
405 }
406}
407
408impl<Octs: AsRef<[u8]>> Ord for UnknownRecordData<Octs> {
409 fn cmp(&self, other: &Self) -> Ordering {
410 self.data.as_ref().cmp(other.data.as_ref())
411 }
412}
413
414impl<Octs: AsRef<[u8]>> ComposeRecordData for UnknownRecordData<Octs> {
417 fn rdlen(&self, _compress: bool) -> Option<u16> {
418 Some(u16::try_from(self.data.as_ref().len()).expect("long rdata"))
419 }
420
421 fn compose_rdata<Target: Composer + ?Sized>(
422 &self,
423 target: &mut Target,
424 ) -> Result<(), Target::AppendError> {
425 target.append_slice(self.data.as_ref())
426 }
427
428 fn compose_canonical_rdata<Target: Composer + ?Sized>(
429 &self,
430 target: &mut Target,
431 ) -> Result<(), Target::AppendError> {
432 self.compose_rdata(target)
433 }
434}
435
436impl<Octs: AsRef<[u8]>> RecordData for UnknownRecordData<Octs> {
439 fn rtype(&self) -> Rtype {
440 self.rtype
441 }
442}
443
444impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
445 for UnknownRecordData<Octs::Range<'a>>
446{
447 fn parse_rdata(
448 rtype: Rtype,
449 parser: &mut Parser<'a, Octs>,
450 ) -> Result<Option<Self>, ParseError> {
451 let rdlen = parser.remaining();
452 parser
453 .parse_octets(rdlen)
454 .map(|data| Some(Self { rtype, data }))
455 .map_err(Into::into)
456 }
457}
458
459impl<Octs: AsRef<[u8]>> fmt::Display for UnknownRecordData<Octs> {
462 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
463 write!(f, "\\# {}", self.data.as_ref().len())?;
464 for ch in self.data.as_ref() {
465 write!(f, " {:02x}", *ch)?
466 }
467 Ok(())
468 }
469}
470
471impl<Octs: AsRef<[u8]>> fmt::Debug for UnknownRecordData<Octs> {
474 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
475 f.write_str("UnknownRecordData(")?;
476 fmt::Display::fmt(self, f)?;
477 f.write_str(")")
478 }
479}
480
481impl<Octs: AsRef<[u8]>> ZonefileFmt for UnknownRecordData<Octs> {
484 fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
485 struct Data<'a>(&'a [u8]);
486
487 impl fmt::Display for Data<'_> {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 write!(f, "\\# {}", self.0.len())?;
490 for ch in self.0 {
491 write!(f, " {:02x}", *ch)?
492 }
493 Ok(())
494 }
495 }
496
497 p.write_token(Data(self.data.as_ref()))
498 }
499}
500
501#[derive(Clone, Copy, Debug)]
507pub struct LongRecordData(());
508
509impl LongRecordData {
510 #[must_use]
511 pub fn as_str(self) -> &'static str {
512 "record data too long"
513 }
514
515 pub fn check_len(len: usize) -> Result<(), Self> {
516 if len > usize::from(u16::MAX) {
517 Err(Self(()))
518 } else {
519 Ok(())
520 }
521 }
522
523 pub fn check_append_len(
524 len: usize,
525 extra_len: usize,
526 ) -> Result<(), Self> {
527 Self::check_len(len.checked_add(extra_len).ok_or(Self(()))?)
529 }
530}
531
532impl fmt::Display for LongRecordData {
533 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534 f.write_str(self.as_str())
535 }
536}
537
538#[cfg(feature = "std")]
539impl std::error::Error for LongRecordData {}
540
541#[cfg(test)]
544#[cfg(all(feature = "std", feature = "bytes"))]
545pub(crate) mod test {
546 use super::super::scan::IterScanner;
547 use super::*;
548 use bytes::{Bytes, BytesMut};
549 use core::fmt::Debug;
550 use octseq::builder::infallible;
551 use std::vec::Vec;
552
553 pub fn test_rdlen<R: ComposeRecordData>(data: R) {
562 let mut buf = Vec::new();
563 infallible(data.compose_rdata(&mut buf));
564 assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
565 buf.clear();
566 infallible(data.compose_canonical_rdata(&mut buf));
567 assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
568 }
569
570 pub fn test_compose_parse<In, F, Out>(data: &In, parse: F)
572 where
573 In: ComposeRecordData + PartialEq<Out> + Debug,
574 F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
575 Out: Debug,
576 {
577 let mut buf = BytesMut::new();
578 infallible(data.compose_rdata(&mut buf));
579 let buf = buf.freeze();
580 let mut parser = Parser::from_ref(&buf);
581 let parsed = (parse)(&mut parser).unwrap();
582 assert_eq!(parser.remaining(), 0);
583 assert_eq!(*data, parsed);
584 }
585
586 type TestScanner =
587 IterScanner<std::vec::IntoIter<std::string::String>, Vec<u8>>;
588
589 pub fn test_scan<F, T, X>(input: &[&str], scan: F, expected: &X)
591 where
592 F: FnOnce(
593 &mut TestScanner,
594 ) -> Result<T, <TestScanner as Scanner>::Error>,
595 T: Debug,
596 X: Debug + PartialEq<T>,
597 {
598 let mut scanner = IterScanner::new(
599 input
600 .iter()
601 .map(|s| std::string::String::from(*s))
602 .collect::<Vec<_>>(),
603 );
604 assert_eq!(*expected, scan(&mut scanner).unwrap(),);
605 assert!(scanner.is_exhausted());
606 }
607}