domain/base/name/
dname.rs

1//! Uncompressed, absolute domain names.
2//!
3//! This is a private module. Its public types are re-exported by the parent.
4
5use super::super::cmp::CanonicalOrd;
6use super::super::scan::{Scanner, Symbol, Symbols};
7use super::super::wire::{FormError, ParseError};
8use super::builder::{DnameBuilder, FromStrError};
9use super::label::{Label, LabelTypeError, SplitLabelError};
10use super::relative::{DnameIter, RelativeDname};
11use super::traits::{FlattenInto, ToDname, ToLabelIter};
12#[cfg(feature = "bytes")]
13use bytes::Bytes;
14use core::ops::{Bound, RangeBounds};
15use core::str::FromStr;
16use core::{borrow, cmp, fmt, hash, str};
17use octseq::builder::{
18    EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, Truncate,
19};
20use octseq::octets::{Octets, OctetsFrom};
21use octseq::parse::Parser;
22#[cfg(feature = "serde")]
23use octseq::serde::{DeserializeOctets, SerializeOctets};
24#[cfg(feature = "std")]
25use std::vec::Vec;
26
27//------------ Dname ---------------------------------------------------------
28
29/// An uncompressed, absolute domain name.
30///
31/// The type wraps an octets sequence that contains an absolute domain name in
32/// wire-format encoding. It provides an interface similar to a slice of the
33/// labels of the name, i.e., you can iterate over the labels, split them off,
34/// etc.
35///
36/// You can construct a domain name from a string via the `FromStr` trait or
37/// manually via a [`DnameBuilder`]. In addition, you can also parse it from
38/// a message. This will, however, require the name to be uncompressed.
39/// Otherwise, you would receive a [`ParsedDname`] which can be converted into
40/// `Dname` via [`ToDname::to_dname`].
41///
42/// The canonical way to convert a domain name into its presentation format is
43/// using [`to_string`] or by using its [`Display`] implementation (which
44/// performs no allocations).
45///
46/// [`DnameBuilder`]: struct.DnameBuilder.html
47/// [`ParsedDname`]: struct.ParsedDname.html
48/// [`RelativeDname`]: struct.RelativeDname.html
49/// [`ToDname::to_dname`]: trait.ToDname.html#method.to_dname
50/// [`to_string`]: `std::string::ToString::to_string`
51/// [`Display`]: `std::fmt::Display`
52#[derive(Clone)]
53pub struct Dname<Octs: ?Sized>(Octs);
54
55impl Dname<()> {
56    /// Domain names have a maximum length of 255 octets.
57    pub const MAX_LEN: usize = 255;
58}
59
60/// # Creating Values
61///
62impl<Octs> Dname<Octs> {
63    /// Creates a domain name from the underlying octets without any check.
64    ///
65    /// Since this will allow to actually construct an incorrectly encoded
66    /// domain name value, the function is unsafe.
67    ///
68    /// # Safety
69    ///
70    /// The octets sequence passed in `octets` must contain a correctly
71    /// encoded absolute domain name. It must be at most 255 octets long.
72    /// It must contain the root label exactly once as its last label.
73    pub const unsafe fn from_octets_unchecked(octets: Octs) -> Self {
74        Dname(octets)
75    }
76
77    /// Creates a domain name from an octet sequence.
78    ///
79    /// This will only succeed if `octets` contains a properly encoded
80    /// absolute domain name in wire format. Because the function checks for
81    /// correctness, this will take a wee bit of time.
82    pub fn from_octets(octets: Octs) -> Result<Self, DnameError>
83    where
84        Octs: AsRef<[u8]>,
85    {
86        Dname::check_slice(octets.as_ref())?;
87        Ok(unsafe { Dname::from_octets_unchecked(octets) })
88    }
89
90    pub fn from_symbols<Sym>(symbols: Sym) -> Result<Self, FromStrError>
91    where
92        Octs: FromBuilder,
93        <Octs as FromBuilder>::Builder: EmptyBuilder
94            + FreezeBuilder<Octets = Octs>
95            + AsRef<[u8]>
96            + AsMut<[u8]>,
97        Sym: IntoIterator<Item = Symbol>,
98    {
99        // DnameBuilder can’t deal with a single dot, so we need to special
100        // case that.
101        let mut symbols = symbols.into_iter();
102        let first = match symbols.next() {
103            Some(first) => first,
104            None => return Err(FromStrError::UnexpectedEnd),
105        };
106        if first == Symbol::Char('.') {
107            if symbols.next().is_some() {
108                return Err(FromStrError::EmptyLabel);
109            } else {
110                // Make a root name.
111                let mut builder =
112                    <Octs as FromBuilder>::Builder::with_capacity(1);
113                builder
114                    .append_slice(b"\0")
115                    .map_err(|_| FromStrError::ShortBuf)?;
116                return Ok(unsafe {
117                    Self::from_octets_unchecked(builder.freeze())
118                });
119            }
120        }
121
122        let mut builder = DnameBuilder::<Octs::Builder>::new();
123        builder.push_symbol(first)?;
124        builder.append_symbols(symbols)?;
125        builder.into_dname().map_err(Into::into)
126    }
127
128    /// Creates a domain name from a sequence of characters.
129    ///
130    /// The sequence must result in a domain name in representation format.
131    /// That is, its labels should be separated by dots.
132    /// Actual dots, white space and backslashes should be escaped by a
133    /// preceeding backslash, and any byte value that is not a printable
134    /// ASCII character should be encoded by a backslash followed by its
135    /// three digit decimal value.
136    ///
137    /// If Internationalized Domain Names are to be used, the labels already
138    /// need to be in punycode-encoded form.
139    ///
140    /// The name will always be an absolute name. If the last character in the
141    /// sequence is not a dot, the function will quietly add a root label,
142    /// anyway. In most cases, this is likely what you want. If it isn’t,
143    /// though, use [`UncertainDname`] instead to be able to check.
144    ///
145    /// [`UncertainDname`]: enum.UncertainDname.html
146    pub fn from_chars<C>(chars: C) -> Result<Self, FromStrError>
147    where
148        Octs: FromBuilder,
149        <Octs as FromBuilder>::Builder: EmptyBuilder
150            + FreezeBuilder<Octets = Octs>
151            + AsRef<[u8]>
152            + AsMut<[u8]>,
153        C: IntoIterator<Item = char>,
154    {
155        Symbols::with(chars.into_iter(), |symbols| {
156            Self::from_symbols(symbols)
157        })
158    }
159
160    /// Reads a name in presentation format from the beginning of a scanner.
161    pub fn scan<S: Scanner<Dname = Self>>(
162        scanner: &mut S,
163    ) -> Result<Self, S::Error> {
164        scanner.scan_dname()
165    }
166
167    /// Returns a domain name consisting of the root label only.
168    ///
169    /// This function will work for any kind octets sequence that can be
170    /// created from an octets slice. Since this will require providing the
171    /// type parameter in some cases, there are shortcuts methods for specific
172    /// octets types: [`root_ref`], [`root_vec`], and [`root_bytes`].
173    ///
174    /// [`root_ref`]: #method.root_ref
175    /// [`root_vec`]: #method.root_vec
176    /// [`root_bytes`]: #method.root_bytes
177    #[must_use]
178    pub fn root() -> Self
179    where
180        Octs: From<&'static [u8]>,
181    {
182        unsafe { Self::from_octets_unchecked(b"\0".as_ref().into()) }
183    }
184}
185
186impl Dname<[u8]> {
187    /// Creates a domain name from an octet slice without checking,
188    unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
189        &*(slice as *const [u8] as *const Dname<[u8]>)
190    }
191
192    /// Creates a domain name from an octets slice.
193    ///
194    /// Note that the input must be in wire format, as shown below.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use domain::base::name::Dname;
200    /// Dname::from_slice(b"\x07example\x03com");
201    /// ```
202    ///
203    /// # Errors
204    ///
205    /// This will only succeed if `slice` contains a properly encoded
206    /// absolute domain name.
207    pub fn from_slice(slice: &[u8]) -> Result<&Self, DnameError> {
208        Self::check_slice(slice)?;
209        Ok(unsafe { Self::from_slice_unchecked(slice) })
210    }
211
212    /// Creates a domain name for the root label only atop an octets slice.
213    #[must_use]
214    pub fn root_slice() -> &'static Self {
215        unsafe { Self::from_slice_unchecked("\0".as_ref()) }
216    }
217
218    /// Checks whether an octet slice contains a correctly encoded name.
219    fn check_slice(mut slice: &[u8]) -> Result<(), DnameError> {
220        if slice.len() > Dname::MAX_LEN {
221            return Err(DnameError::LongName);
222        }
223        loop {
224            let (label, tail) = Label::split_from(slice)?;
225            if label.is_root() {
226                if tail.is_empty() {
227                    break;
228                } else {
229                    return Err(DnameError::TrailingData);
230                }
231            }
232            if tail.is_empty() {
233                return Err(DnameError::RelativeName);
234            }
235            slice = tail;
236        }
237        Ok(())
238    }
239}
240
241impl Dname<&'static [u8]> {
242    /// Creates a domain name for the root label only atop a slice reference.
243    #[must_use]
244    pub fn root_ref() -> Self {
245        Self::root()
246    }
247}
248
249#[cfg(feature = "std")]
250impl Dname<Vec<u8>> {
251    /// Creates a domain name for the root label only atop a `Vec<u8>`.
252    #[must_use]
253    pub fn root_vec() -> Self {
254        Self::root()
255    }
256
257    /// Creates a domain name atop a `Vec<u8>` from its string representation.
258    pub fn vec_from_str(s: &str) -> Result<Self, FromStrError> {
259        FromStr::from_str(s)
260    }
261}
262
263#[cfg(feature = "bytes")]
264impl Dname<Bytes> {
265    /// Creates a domain name for the root label only atop a bytes values.
266    pub fn root_bytes() -> Self {
267        Self::root()
268    }
269
270    /// Creates a domain name atop a Bytes from its string representation.
271    pub fn bytes_from_str(s: &str) -> Result<Self, FromStrError> {
272        FromStr::from_str(s)
273    }
274}
275
276/// # Conversions
277///
278impl<Octs: ?Sized> Dname<Octs> {
279    /// Returns a reference to the underlying octets sequence.
280    ///
281    /// These octets contain the domain name in wire format.
282    pub fn as_octets(&self) -> &Octs {
283        &self.0
284    }
285
286    /// Converts the domain name into the underlying octets sequence.
287    pub fn into_octets(self) -> Octs
288    where
289        Octs: Sized,
290    {
291        self.0
292    }
293
294    /// Converts the name into a relative name by dropping the root label.
295    pub fn into_relative(mut self) -> RelativeDname<Octs>
296    where
297        Octs: Sized + AsRef<[u8]> + Truncate,
298    {
299        let len = self.0.as_ref().len() - 1;
300        self.0.truncate(len);
301        unsafe { RelativeDname::from_octets_unchecked(self.0) }
302    }
303
304    /// Returns a domain name using a reference to the octets.
305    pub fn for_ref(&self) -> Dname<&Octs> {
306        unsafe { Dname::from_octets_unchecked(&self.0) }
307    }
308
309    /// Returns a reference to the underlying octets slice.
310    ///
311    /// The slice will contain the domain name in wire format.
312    pub fn as_slice(&self) -> &[u8]
313    where
314        Octs: AsRef<[u8]>,
315    {
316        self.0.as_ref()
317    }
318
319    /// Returns a domain name for the octets slice of the content.
320    pub fn for_slice(&self) -> &Dname<[u8]>
321    where
322        Octs: AsRef<[u8]>,
323    {
324        unsafe { Dname::from_slice_unchecked(self.0.as_ref()) }
325    }
326
327    /// Converts the domain name into its canonical form.
328    ///
329    /// This will convert all octets that are upper case ASCII characters
330    /// into their lower case equivalent.
331    pub fn make_canonical(&mut self)
332    where
333        Octs: AsMut<[u8]>,
334    {
335        Label::make_slice_canonical(self.0.as_mut());
336    }
337}
338
339/// # Properties
340///
341impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
342    /// Returns whether the name is the root label only.
343    pub fn is_root(&self) -> bool {
344        self.0.as_ref().len() == 1
345    }
346
347    /// Returns the length of the domain name.
348    #[allow(clippy::len_without_is_empty)] // never empty ...
349    pub fn len(&self) -> usize {
350        self.0.as_ref().len()
351    }
352
353    pub fn fmt_with_dot(&self) -> impl fmt::Display + '_ {
354        DisplayWithDot(self.for_slice())
355    }
356}
357
358/// # Working with Labels
359///
360impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
361    /// Returns an iterator over the labels of the domain name.
362    pub fn iter(&self) -> DnameIter {
363        DnameIter::new(self.0.as_ref())
364    }
365
366    /// Returns an iterator over the suffixes of the name.
367    ///
368    /// The returned iterator starts with the full name and then for each
369    /// additional step returns a name with the left-most label stripped off
370    /// until it reaches the root label.
371    pub fn iter_suffixes(&self) -> SuffixIter<'_, Octs> {
372        SuffixIter::new(self)
373    }
374
375    /// Returns the number of labels in the domain name.
376    pub fn label_count(&self) -> usize {
377        self.iter().count()
378    }
379
380    /// Returns a reference to the first label.
381    pub fn first(&self) -> &Label {
382        self.iter().next().unwrap()
383    }
384
385    /// Returns a reference to the last label.
386    ///
387    /// Because the last label in an absolute name is always the root label,
388    /// this method can return a static reference. It is also a wee bit silly,
389    /// but here for completeness.
390    pub fn last(&self) -> &'static Label {
391        Label::root()
392    }
393
394    /// Determines whether `base` is a prefix of `self`.
395    pub fn starts_with<'a, N: ToLabelIter + ?Sized>(
396        &'a self,
397        base: &'a N,
398    ) -> bool {
399        <Self as ToLabelIter>::starts_with(self, base)
400    }
401
402    /// Determines whether `base` is a suffix of `self`.
403    pub fn ends_with<'a, N: ToLabelIter + ?Sized>(
404        &'a self,
405        base: &'a N,
406    ) -> bool {
407        <Self as ToLabelIter>::ends_with(self, base)
408    }
409
410    /// Returns whether an index points to the first byte of a non-root label.
411    pub fn is_label_start(&self, mut index: usize) -> bool {
412        if index == 0 {
413            return true;
414        }
415        let mut tmp = self.as_slice();
416        while !tmp.is_empty() {
417            let (label, tail) = Label::split_from(tmp).unwrap();
418            let len = label.len() + 1;
419            if index < len || len == 1 {
420                // length 1: root label.
421                return false;
422            } else if index == len {
423                return true;
424            }
425            index -= len;
426            tmp = tail;
427        }
428        false
429    }
430
431    /// Like `is_label_start` but panics if it isn’t.
432    fn check_index(&self, index: usize) {
433        if !self.is_label_start(index) {
434            panic!("index not at start of a label");
435        }
436    }
437
438    /// Checks that a range starts and ends at label bounds.
439    fn check_bounds(&self, bounds: &impl RangeBounds<usize>) {
440        match bounds.start_bound().cloned() {
441            Bound::Included(idx) => self.check_index(idx),
442            Bound::Excluded(_) => {
443                panic!("excluded lower bounds not supported");
444            }
445            Bound::Unbounded => {}
446        }
447        match bounds.end_bound().cloned() {
448            Bound::Included(idx) => self
449                .check_index(idx.checked_add(1).expect("end bound too big")),
450            Bound::Excluded(idx) => self.check_index(idx),
451            Bound::Unbounded => {
452                panic!("unbounded end bound (results in absolute name)")
453            }
454        }
455    }
456
457    /// Returns the part of the name indicated by start and end positions.
458    ///
459    /// The returned name will start at position `begin` and end right before
460    /// position `end`. Both positions are given as indexes into the
461    /// underlying octets sequence and must point to the begining of a label.
462    ///
463    /// The method returns a reference to an unsized relative domain name and
464    /// is thus best suited for temporary referencing. If you want to keep the
465    /// part of the name around, [`range`] is likely a better choice.
466    ///
467    /// # Panics
468    ///
469    /// The method panics if either position is not the start of a label or
470    /// is out of bounds.
471    ///
472    /// Because the returned domain name is relative, the method will also
473    /// panic if the end is equal to the length of the name. If you
474    /// want to slice the entire end of the name including the final root
475    /// label, you can use [`slice_from()`] instead.
476    ///
477    /// [`range`]: #method.range
478    /// [`slice_from()`]: #method.slice_from
479    pub fn slice(
480        &self,
481        range: impl RangeBounds<usize>,
482    ) -> &RelativeDname<[u8]> {
483        self.check_bounds(&range);
484        unsafe {
485            RelativeDname::from_slice_unchecked(self.0.as_ref().range(range))
486        }
487    }
488
489    /// Returns the part of the name starting at the given position.
490    ///
491    /// The returned name will start at the given postion and cover the
492    /// remainder of the name. The position `begin` is provided as an index
493    /// into the underlying octets sequence and must point to the beginning
494    /// of a label.
495    ///
496    /// The method returns a reference to an unsized domain name and
497    /// is thus best suited for temporary referencing. If you want to keep the
498    /// part of the name around, [`range_from`] is likely a better choice.
499    ///
500    /// # Panics
501    ///
502    /// The method panics if `begin` isn’t the index of the beginning of a
503    /// label or is out of bounds.
504    ///
505    /// [`range_from`]: #method.range_from
506    pub fn slice_from(&self, begin: usize) -> &Dname<[u8]> {
507        self.check_index(begin);
508        unsafe { Dname::from_slice_unchecked(&self.0.as_ref()[begin..]) }
509    }
510
511    /// Returns the part of the name indicated by start and end positions.
512    ///
513    /// The returned name will start at position `begin` and end right before
514    /// position `end`. Both positions are given as indexes into the
515    /// underlying octets sequence and must point to the begining of a label.
516    ///
517    /// # Panics
518    ///
519    /// The method panics if either position is not the start of a label or
520    /// is out of bounds.
521    ///
522    /// Because the returned domain name is relative, the method will also
523    /// panic if the end is equal to the length of the name. If you
524    /// want to slice the entire end of the name including the final root
525    /// label, you can use [`range_from()`] instead.
526    ///
527    /// [`range_from()`]: #method.range_from
528    pub fn range(
529        &self,
530        range: impl RangeBounds<usize>,
531    ) -> RelativeDname<<Octs as Octets>::Range<'_>>
532    where
533        Octs: Octets,
534    {
535        self.check_bounds(&range);
536        unsafe { RelativeDname::from_octets_unchecked(self.0.range(range)) }
537    }
538
539    /// Returns the part of the name starting at the given position.
540    ///
541    /// The returned name will start at the given postion and cover the
542    /// remainder of the name. The position `begin` is provided as an index
543    /// into the underlying octets sequence and must point to the beginning
544    /// of a label.
545    ///
546    /// # Panics
547    ///
548    /// The method panics if `begin` isn’t the index of the beginning of a
549    /// label or is out of bounds.
550    pub fn range_from(
551        &self,
552        begin: usize,
553    ) -> Dname<<Octs as Octets>::Range<'_>>
554    where
555        Octs: Octets,
556    {
557        self.check_index(begin);
558        unsafe { self.range_from_unchecked(begin) }
559    }
560
561    /// Returns the part of the name starting at a position without checking.
562    unsafe fn range_from_unchecked(
563        &self,
564        begin: usize,
565    ) -> Dname<<Octs as Octets>::Range<'_>>
566    where
567        Octs: Octets,
568    {
569        Dname::from_octets_unchecked(self.0.range(begin..))
570    }
571}
572
573impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
574    /// Splits the name into two at the given position.
575    ///
576    /// Returns a pair of the left and right part of the split name.
577    ///
578    /// # Panics
579    ///
580    /// The method will panic if `mid` is not the index of the beginning of
581    /// a label or if it is out of bounds.
582    pub fn split(
583        &self,
584        mid: usize,
585    ) -> (RelativeDname<Octs::Range<'_>>, Dname<Octs::Range<'_>>)
586    where
587        Octs: Octets,
588    {
589        self.check_index(mid);
590        unsafe {
591            (
592                RelativeDname::from_octets_unchecked(self.0.range(..mid)),
593                Dname::from_octets_unchecked(self.0.range(mid..)),
594            )
595        }
596    }
597
598    /// Truncates the name before `len`.
599    ///
600    /// Because truncating converts the name into a relative name, the method
601    /// consumes self.
602    ///
603    /// # Panics
604    ///
605    /// The method will panic if `len` is not the index of a new label or if
606    /// it is out of bounds.
607    pub fn truncate(mut self, len: usize) -> RelativeDname<Octs>
608    where
609        Octs: Truncate + Sized,
610    {
611        self.check_index(len);
612        self.0.truncate(len);
613        unsafe { RelativeDname::from_octets_unchecked(self.0) }
614    }
615
616    /// Splits off the first label.
617    ///
618    /// If this name is longer than just the root label, returns a pair
619    /// of that label and the remaining name. If the name is only the root
620    /// label, returns `None`.
621    pub fn split_first(&self) -> Option<(&Label, Dname<Octs::Range<'_>>)>
622    where
623        Octs: Octets,
624    {
625        if self.compose_len() == 1 {
626            return None;
627        }
628        let label = self.iter().next().unwrap();
629        Some((label, self.split(label.len() + 1).1))
630    }
631
632    /// Returns the parent of the current name.
633    ///
634    /// If the name consists of the root label only, returns `None`.
635    pub fn parent(&self) -> Option<Dname<Octs::Range<'_>>>
636    where
637        Octs: Octets,
638    {
639        self.split_first().map(|(_, parent)| parent)
640    }
641
642    /// Strips the suffix `base` from the domain name.
643    ///
644    /// If `base` is indeed a suffix, returns a relative domain name with the
645    /// remainder of the name. Otherwise, returns an error with an unmodified
646    /// `self`.
647    pub fn strip_suffix<N: ToDname + ?Sized>(
648        self,
649        base: &N,
650    ) -> Result<RelativeDname<Octs>, Self>
651    where
652        Octs: Truncate + Sized,
653    {
654        if self.ends_with(base) {
655            let len = self.0.as_ref().len() - usize::from(base.compose_len());
656            Ok(self.truncate(len))
657        } else {
658            Err(self)
659        }
660    }
661}
662
663impl<Octs> Dname<Octs> {
664    /// Reads a name in wire format from the beginning of a parser.
665    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
666        parser: &mut Parser<'a, Src>,
667    ) -> Result<Self, ParseError> {
668        let len = Self::parse_name_len(parser)?;
669        Ok(unsafe { Self::from_octets_unchecked(parser.parse_octets(len)?) })
670    }
671
672    /// Peeks at a parser and returns the length of a name at its beginning.
673    fn parse_name_len<Source: AsRef<[u8]> + ?Sized>(
674        parser: &Parser<Source>,
675    ) -> Result<usize, ParseError> {
676        let len = {
677            let mut tmp = parser.peek_all();
678            loop {
679                if tmp.is_empty() {
680                    return Err(ParseError::ShortInput);
681                }
682                let (label, tail) = Label::split_from(tmp)?;
683                tmp = tail;
684                if label.is_root() {
685                    break;
686                }
687            }
688            parser.remaining() - tmp.len()
689        };
690        if len > Dname::MAX_LEN {
691            Err(DnameError::LongName.into())
692        } else {
693            Ok(len)
694        }
695    }
696}
697
698//--- AsRef
699
700impl<Octs> AsRef<Octs> for Dname<Octs> {
701    fn as_ref(&self) -> &Octs {
702        &self.0
703    }
704}
705
706impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Dname<Octs> {
707    fn as_ref(&self) -> &[u8] {
708        self.0.as_ref()
709    }
710}
711
712//--- OctetsFrom
713
714impl<Octs, SrcOcts> OctetsFrom<Dname<SrcOcts>> for Dname<Octs>
715where
716    Octs: OctetsFrom<SrcOcts>,
717{
718    type Error = Octs::Error;
719
720    fn try_octets_from(source: Dname<SrcOcts>) -> Result<Self, Self::Error> {
721        Octs::try_octets_from(source.0)
722            .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
723    }
724}
725
726//--- FromStr
727
728impl<Octs> FromStr for Dname<Octs>
729where
730    Octs: FromBuilder,
731    <Octs as FromBuilder>::Builder: EmptyBuilder
732        + FreezeBuilder<Octets = Octs>
733        + AsRef<[u8]>
734        + AsMut<[u8]>,
735{
736    type Err = FromStrError;
737
738    /// Parses a string into an absolute domain name.
739    ///
740    /// The name needs to be formatted in representation format, i.e., as a
741    /// sequence of labels separated by dots. If Internationalized Domain
742    /// Name (IDN) labels are to be used, these need to be given in punycode
743    /// encoded form.
744    ///
745    /// The implementation assumes that the string refers to an absolute name
746    /// whether it ends in a dot or not. If you need to be able to distinguish
747    /// between those two cases, you can use [`UncertainDname`] instead.
748    ///
749    /// [`UncertainDname`]: struct.UncertainDname.html
750    fn from_str(s: &str) -> Result<Self, Self::Err> {
751        Self::from_chars(s.chars())
752    }
753}
754
755//--- FlattenInto
756
757impl<Octs, Target> FlattenInto<Dname<Target>> for Dname<Octs>
758where
759    Target: OctetsFrom<Octs>,
760{
761    type AppendError = Target::Error;
762
763    fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
764        Target::try_octets_from(self.0)
765            .map(|octets| unsafe { Dname::from_octets_unchecked(octets) })
766    }
767}
768
769//--- PartialEq, and Eq
770
771impl<Octs, N> PartialEq<N> for Dname<Octs>
772where
773    Octs: AsRef<[u8]> + ?Sized,
774    N: ToDname + ?Sized,
775{
776    fn eq(&self, other: &N) -> bool {
777        self.name_eq(other)
778    }
779}
780
781impl<Octs: AsRef<[u8]> + ?Sized> Eq for Dname<Octs> {}
782
783//--- PartialOrd, Ord, and CanonicalOrd
784
785impl<Octs, N> PartialOrd<N> for Dname<Octs>
786where
787    Octs: AsRef<[u8]> + ?Sized,
788    N: ToDname + ?Sized,
789{
790    /// Returns the ordering between `self` and `other`.
791    ///
792    /// Domain name order is determined according to the ‘canonical DNS
793    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
794    ///
795    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
796    fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
797        Some(self.name_cmp(other))
798    }
799}
800
801impl<Octs: AsRef<[u8]> + ?Sized> Ord for Dname<Octs> {
802    /// Returns the ordering between `self` and `other`.
803    ///
804    /// Domain name order is determined according to the ‘canonical DNS
805    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
806    ///
807    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
808    fn cmp(&self, other: &Self) -> cmp::Ordering {
809        self.name_cmp(other)
810    }
811}
812
813impl<Octs, N> CanonicalOrd<N> for Dname<Octs>
814where
815    Octs: AsRef<[u8]> + ?Sized,
816    N: ToDname + ?Sized,
817{
818    fn canonical_cmp(&self, other: &N) -> cmp::Ordering {
819        self.name_cmp(other)
820    }
821}
822
823//--- Hash
824
825impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Dname<Octs> {
826    fn hash<H: hash::Hasher>(&self, state: &mut H) {
827        for item in self.iter() {
828            item.hash(state)
829        }
830    }
831}
832
833//--- ToLabelIter and ToDname
834
835impl<Octs> ToLabelIter for Dname<Octs>
836where
837    Octs: AsRef<[u8]> + ?Sized,
838{
839    type LabelIter<'a> = DnameIter<'a> where Octs: 'a;
840
841    fn iter_labels(&self) -> Self::LabelIter<'_> {
842        self.iter()
843    }
844
845    fn compose_len(&self) -> u16 {
846        u16::try_from(self.0.as_ref().len()).expect("long domain name")
847    }
848}
849
850impl<Octs: AsRef<[u8]> + ?Sized> ToDname for Dname<Octs> {
851    fn as_flat_slice(&self) -> Option<&[u8]> {
852        Some(self.0.as_ref())
853    }
854}
855
856//--- IntoIterator
857
858impl<'a, Octs> IntoIterator for &'a Dname<Octs>
859where
860    Octs: AsRef<[u8]> + ?Sized,
861{
862    type Item = &'a Label;
863    type IntoIter = DnameIter<'a>;
864
865    fn into_iter(self) -> Self::IntoIter {
866        self.iter()
867    }
868}
869
870//--- Display
871
872impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Dname<Octs> {
873    /// Formats the domain name.
874    ///
875    /// This will produce the domain name in ‘common display format’ without
876    /// the trailing dot with the exception of a root name which will be just
877    /// a dot.
878    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
879        if self.is_root() {
880            return f.write_str(".");
881        }
882
883        let mut iter = self.iter();
884        write!(f, "{}", iter.next().unwrap())?;
885        for label in iter {
886            if !label.is_root() {
887                write!(f, ".{}", label)?
888            }
889        }
890        Ok(())
891    }
892}
893
894//--- Debug
895
896impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Dname<Octs> {
897    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
898        write!(f, "Dname({})", self.fmt_with_dot())
899    }
900}
901
902//--- AsRef and Borrow
903
904impl<Octs: AsRef<[u8]>> AsRef<Dname<[u8]>> for Dname<Octs> {
905    fn as_ref(&self) -> &Dname<[u8]> {
906        self.for_slice()
907    }
908}
909
910/// Borrow a domain name.
911///
912/// Containers holding an owned `Dname<_>` may be queried with name over a
913/// slice. This `Borrow<_>` impl supports user code querying containers with
914/// compatible-but-different types like the following example:
915///
916/// ```
917/// use std::collections::HashMap;
918///
919/// use domain::base::Dname;
920///
921/// fn get_description(
922///     hash: &HashMap<Dname<Vec<u8>>, String>
923/// ) -> Option<&str> {
924///     let lookup_name: &Dname<[u8]> =
925///         Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
926///     hash.get(lookup_name).map(|x| x.as_ref())
927/// }
928/// ```
929impl<Octs: AsRef<[u8]>> borrow::Borrow<Dname<[u8]>> for Dname<Octs> {
930    fn borrow(&self) -> &Dname<[u8]> {
931        self.for_slice()
932    }
933}
934
935//--- Serialize and Deserialize
936
937#[cfg(feature = "serde")]
938impl<Octs> serde::Serialize for Dname<Octs>
939where
940    Octs: AsRef<[u8]> + SerializeOctets + ?Sized,
941{
942    fn serialize<S: serde::Serializer>(
943        &self,
944        serializer: S,
945    ) -> Result<S::Ok, S::Error> {
946        if serializer.is_human_readable() {
947            serializer
948                .serialize_newtype_struct("Dname", &format_args!("{}", self))
949        } else {
950            serializer.serialize_newtype_struct(
951                "Dname",
952                &self.0.as_serialized_octets(),
953            )
954        }
955    }
956}
957
958#[cfg(feature = "serde")]
959impl<'de, Octs> serde::Deserialize<'de> for Dname<Octs>
960where
961    Octs: FromBuilder + DeserializeOctets<'de>,
962    <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
963        + EmptyBuilder
964        + AsRef<[u8]>
965        + AsMut<[u8]>,
966{
967    fn deserialize<D: serde::Deserializer<'de>>(
968        deserializer: D,
969    ) -> Result<Self, D::Error> {
970        use core::marker::PhantomData;
971
972        struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
973
974        impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
975        where
976            Octs: FromBuilder + DeserializeOctets<'de>,
977            <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
978                + EmptyBuilder
979                + AsRef<[u8]>
980                + AsMut<[u8]>,
981        {
982            type Value = Dname<Octs>;
983
984            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
985                f.write_str("an absolute domain name")
986            }
987
988            fn visit_str<E: serde::de::Error>(
989                self,
990                v: &str,
991            ) -> Result<Self::Value, E> {
992                Dname::from_str(v).map_err(E::custom)
993            }
994
995            fn visit_borrowed_bytes<E: serde::de::Error>(
996                self,
997                value: &'de [u8],
998            ) -> Result<Self::Value, E> {
999                self.0.visit_borrowed_bytes(value).and_then(|octets| {
1000                    Dname::from_octets(octets).map_err(E::custom)
1001                })
1002            }
1003
1004            #[cfg(feature = "std")]
1005            fn visit_byte_buf<E: serde::de::Error>(
1006                self,
1007                value: std::vec::Vec<u8>,
1008            ) -> Result<Self::Value, E> {
1009                self.0.visit_byte_buf(value).and_then(|octets| {
1010                    Dname::from_octets(octets).map_err(E::custom)
1011                })
1012            }
1013        }
1014
1015        struct NewtypeVisitor<T>(PhantomData<T>);
1016
1017        impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
1018        where
1019            Octs: FromBuilder + DeserializeOctets<'de>,
1020            <Octs as FromBuilder>::Builder: EmptyBuilder
1021                + FreezeBuilder<Octets = Octs>
1022                + AsRef<[u8]>
1023                + AsMut<[u8]>,
1024        {
1025            type Value = Dname<Octs>;
1026
1027            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1028                f.write_str("an absolute domain name")
1029            }
1030
1031            fn visit_newtype_struct<D: serde::Deserializer<'de>>(
1032                self,
1033                deserializer: D,
1034            ) -> Result<Self::Value, D::Error> {
1035                if deserializer.is_human_readable() {
1036                    deserializer
1037                        .deserialize_str(InnerVisitor(Octs::visitor()))
1038                } else {
1039                    Octs::deserialize_with_visitor(
1040                        deserializer,
1041                        InnerVisitor(Octs::visitor()),
1042                    )
1043                }
1044            }
1045        }
1046
1047        deserializer
1048            .deserialize_newtype_struct("Dname", NewtypeVisitor(PhantomData))
1049    }
1050}
1051
1052//------------ SuffixIter ----------------------------------------------------
1053
1054/// An iterator over ever shorter suffixes of a domain name.
1055#[derive(Clone)]
1056pub struct SuffixIter<'a, Octs: ?Sized> {
1057    name: &'a Dname<Octs>,
1058    start: Option<usize>,
1059}
1060
1061impl<'a, Octs: ?Sized> SuffixIter<'a, Octs> {
1062    /// Creates a new iterator cloning `name`.
1063    fn new(name: &'a Dname<Octs>) -> Self {
1064        SuffixIter {
1065            name,
1066            start: Some(0),
1067        }
1068    }
1069}
1070
1071impl<'a, Octs: Octets + ?Sized> Iterator for SuffixIter<'a, Octs> {
1072    type Item = Dname<Octs::Range<'a>>;
1073
1074    fn next(&mut self) -> Option<Self::Item> {
1075        let start = self.start?;
1076        let res = unsafe { self.name.range_from_unchecked(start) };
1077        let label = res.first();
1078        if label.is_root() {
1079            self.start = None;
1080        } else {
1081            self.start = Some(start + usize::from(label.compose_len()))
1082        }
1083        Some(res)
1084    }
1085}
1086
1087//------------ DisplayWithDot ------------------------------------------------
1088
1089struct DisplayWithDot<'a>(&'a Dname<[u8]>);
1090
1091impl<'a> fmt::Display for DisplayWithDot<'a> {
1092    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1093        if self.0.is_root() {
1094            f.write_str(".")
1095        } else {
1096            let mut iter = self.0.iter();
1097            write!(f, "{}", iter.next().unwrap())?;
1098            for label in iter {
1099                write!(f, ".{}", label)?
1100            }
1101            Ok(())
1102        }
1103    }
1104}
1105
1106//============ Error Types ===================================================
1107
1108//------------ DnameError ----------------------------------------------------
1109
1110/// A domain name wasn’t encoded correctly.
1111#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1112pub enum DnameError {
1113    /// The encoding contained an unknown or disallowed label type.
1114    BadLabel(LabelTypeError),
1115
1116    /// The encoding contained a compression pointer.
1117    CompressedName,
1118
1119    /// The name was longer than 255 octets.
1120    LongName,
1121
1122    /// The name did not end with the root label.
1123    RelativeName,
1124
1125    /// There was more data after the root label was encountered.
1126    TrailingData,
1127
1128    /// The input ended in the middle of a label.
1129    ShortInput,
1130}
1131
1132//--- From
1133
1134impl From<LabelTypeError> for DnameError {
1135    fn from(err: LabelTypeError) -> DnameError {
1136        DnameError::BadLabel(err)
1137    }
1138}
1139
1140impl From<SplitLabelError> for DnameError {
1141    fn from(err: SplitLabelError) -> DnameError {
1142        match err {
1143            SplitLabelError::Pointer(_) => DnameError::CompressedName,
1144            SplitLabelError::BadType(t) => DnameError::BadLabel(t),
1145            SplitLabelError::ShortInput => DnameError::ShortInput,
1146        }
1147    }
1148}
1149
1150impl From<DnameError> for FormError {
1151    fn from(err: DnameError) -> FormError {
1152        FormError::new(match err {
1153            DnameError::BadLabel(_) => "unknown label type",
1154            DnameError::CompressedName => "compressed domain name",
1155            DnameError::LongName => "long domain name",
1156            DnameError::RelativeName => "relative domain name",
1157            DnameError::TrailingData => "trailing data in buffer",
1158            DnameError::ShortInput => "unexpected end of buffer",
1159        })
1160    }
1161}
1162
1163impl From<DnameError> for ParseError {
1164    fn from(err: DnameError) -> ParseError {
1165        match err {
1166            DnameError::ShortInput => ParseError::ShortInput,
1167            other => ParseError::Form(other.into()),
1168        }
1169    }
1170}
1171
1172//--- Display and Error
1173
1174impl fmt::Display for DnameError {
1175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1176        match *self {
1177            DnameError::BadLabel(ref err) => err.fmt(f),
1178            DnameError::CompressedName => {
1179                f.write_str("compressed domain name")
1180            }
1181            DnameError::LongName => f.write_str("long domain name"),
1182            DnameError::RelativeName => f.write_str("relative name"),
1183            DnameError::TrailingData => f.write_str("trailing data"),
1184            DnameError::ShortInput => ParseError::ShortInput.fmt(f),
1185        }
1186    }
1187}
1188
1189#[cfg(feature = "std")]
1190impl std::error::Error for DnameError {}
1191
1192//============ Testing =======================================================
1193//
1194// Some of the helper functions herein are resused by the tests of other
1195// sub-modules of ::bits::name. Hence the `pub(crate)` designation.
1196
1197#[cfg(test)]
1198pub(crate) mod test {
1199    use super::*;
1200
1201    #[cfg(feature = "std")]
1202    macro_rules! assert_panic {
1203        ( $cond:expr ) => {{
1204            let result = std::panic::catch_unwind(|| $cond);
1205            assert!(result.is_err());
1206        }};
1207    }
1208
1209    #[test]
1210    fn impls() {
1211        fn assert_to_dname<T: ToDname + ?Sized>(_: &T) {}
1212
1213        assert_to_dname(Dname::from_slice(b"\0".as_ref()).unwrap());
1214        assert_to_dname(&Dname::from_octets(b"\0").unwrap());
1215        assert_to_dname(&Dname::from_octets(b"\0".as_ref()).unwrap());
1216
1217        #[cfg(feature = "std")]
1218        {
1219            assert_to_dname(
1220                &Dname::from_octets(Vec::from(b"\0".as_ref())).unwrap(),
1221            );
1222        }
1223    }
1224
1225    #[cfg(feature = "bytes")]
1226    #[test]
1227    fn impls_bytes() {
1228        fn assert_to_dname<T: ToDname + ?Sized>(_: &T) {}
1229
1230        assert_to_dname(
1231            &Dname::from_octets(Bytes::from(b"\0".as_ref())).unwrap(),
1232        );
1233    }
1234
1235    #[test]
1236    fn root() {
1237        assert_eq!(Dname::root_ref().as_slice(), b"\0");
1238        #[cfg(feature = "std")]
1239        {
1240            assert_eq!(Dname::root_vec().as_slice(), b"\0");
1241        }
1242        assert_eq!(Dname::root_slice().as_slice(), b"\0");
1243    }
1244
1245    #[cfg(feature = "bytes")]
1246    #[test]
1247    fn root_bytes() {
1248        assert_eq!(Dname::root_bytes().as_slice(), b"\0");
1249    }
1250
1251    #[test]
1252    #[cfg(feature = "std")]
1253    fn from_slice() {
1254        // a simple good name
1255        assert_eq!(
1256            Dname::from_slice(b"\x03www\x07example\x03com\0")
1257                .unwrap()
1258                .as_slice(),
1259            b"\x03www\x07example\x03com\0"
1260        );
1261
1262        // relative name
1263        assert_eq!(
1264            Dname::from_slice(b"\x03www\x07example\x03com"),
1265            Err(DnameError::RelativeName)
1266        );
1267
1268        // bytes shorter than what label length says.
1269        assert_eq!(
1270            Dname::from_slice(b"\x03www\x07exa"),
1271            Err(DnameError::ShortInput)
1272        );
1273
1274        // label 63 long ok, 64 bad.
1275        let mut slice = [0u8; 65];
1276        slice[0] = 63;
1277        assert!(Dname::from_slice(&slice[..]).is_ok());
1278        let mut slice = [0u8; 66];
1279        slice[0] = 64;
1280        assert!(Dname::from_slice(&slice[..]).is_err());
1281
1282        // name 255 long ok, 256 bad.
1283        let mut buf = std::vec::Vec::new();
1284        for _ in 0..25 {
1285            buf.extend_from_slice(b"\x09123456789");
1286        }
1287        assert_eq!(buf.len(), 250);
1288        let mut tmp = buf.clone();
1289        tmp.extend_from_slice(b"\x03123\0");
1290        assert_eq!(Dname::from_slice(&tmp).map(|_| ()), Ok(()));
1291        buf.extend_from_slice(b"\x041234\0");
1292        assert!(Dname::from_slice(&buf).is_err());
1293
1294        // trailing data
1295        assert!(Dname::from_slice(b"\x03com\0\x03www\0").is_err());
1296
1297        // bad label heads: compressed, other types.
1298        assert_eq!(
1299            Dname::from_slice(b"\xa2asdasds"),
1300            Err(LabelTypeError::Undefined.into())
1301        );
1302        assert_eq!(
1303            Dname::from_slice(b"\x62asdasds"),
1304            Err(LabelTypeError::Extended(0x62).into())
1305        );
1306        assert_eq!(
1307            Dname::from_slice(b"\xccasdasds"),
1308            Err(DnameError::CompressedName)
1309        );
1310
1311        // empty input
1312        assert_eq!(Dname::from_slice(b""), Err(DnameError::ShortInput));
1313    }
1314
1315    // `Dname::from_chars` is covered in the `FromStr` test.
1316    //
1317    // No tests for the simple conversion methods because, well, simple.
1318
1319    #[test]
1320    fn into_relative() {
1321        assert_eq!(
1322            Dname::from_octets(b"\x03www\0".as_ref())
1323                .unwrap()
1324                .into_relative()
1325                .as_slice(),
1326            b"\x03www"
1327        );
1328    }
1329
1330    #[test]
1331    #[cfg(feature = "std")]
1332    fn make_canonical() {
1333        let mut name =
1334            RelativeDname::vec_from_str("wWw.exAmpLE.coM").unwrap();
1335        name.make_canonical();
1336        assert_eq!(
1337            name,
1338            RelativeDname::from_octets(b"\x03www\x07example\x03com").unwrap()
1339        );
1340    }
1341
1342    #[test]
1343    fn is_root() {
1344        assert!(Dname::from_slice(b"\0").unwrap().is_root());
1345        assert!(!Dname::from_slice(b"\x03www\0").unwrap().is_root());
1346        assert!(Dname::root_ref().is_root());
1347    }
1348
1349    pub fn cmp_iter<I>(mut iter: I, labels: &[&[u8]])
1350    where
1351        I: Iterator,
1352        I::Item: AsRef<[u8]>,
1353    {
1354        let mut labels = labels.iter();
1355        loop {
1356            match (iter.next(), labels.next()) {
1357                (Some(left), Some(right)) => {
1358                    assert_eq!(left.as_ref(), *right)
1359                }
1360                (None, None) => break,
1361                (_, None) => panic!("extra items in iterator"),
1362                (None, _) => panic!("missing items in iterator"),
1363            }
1364        }
1365    }
1366
1367    #[test]
1368    fn iter() {
1369        cmp_iter(Dname::root_ref().iter(), &[b""]);
1370        cmp_iter(
1371            Dname::from_slice(b"\x03www\x07example\x03com\0")
1372                .unwrap()
1373                .iter(),
1374            &[b"www", b"example", b"com", b""],
1375        );
1376    }
1377
1378    pub fn cmp_iter_back<I>(mut iter: I, labels: &[&[u8]])
1379    where
1380        I: DoubleEndedIterator,
1381        I::Item: AsRef<[u8]>,
1382    {
1383        let mut labels = labels.iter();
1384        loop {
1385            match (iter.next_back(), labels.next()) {
1386                (Some(left), Some(right)) => {
1387                    assert_eq!(left.as_ref(), *right)
1388                }
1389                (None, None) => break,
1390                (_, None) => panic!("extra items in iterator"),
1391                (None, _) => panic!("missing items in iterator"),
1392            }
1393        }
1394    }
1395
1396    #[test]
1397    fn iter_back() {
1398        cmp_iter_back(Dname::root_ref().iter(), &[b""]);
1399        cmp_iter_back(
1400            Dname::from_slice(b"\x03www\x07example\x03com\0")
1401                .unwrap()
1402                .iter(),
1403            &[b"", b"com", b"example", b"www"],
1404        );
1405    }
1406
1407    #[test]
1408    fn iter_suffixes() {
1409        cmp_iter(Dname::root_ref().iter_suffixes(), &[b"\0"]);
1410        cmp_iter(
1411            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1412                .unwrap()
1413                .iter_suffixes(),
1414            &[
1415                b"\x03www\x07example\x03com\0",
1416                b"\x07example\x03com\0",
1417                b"\x03com\0",
1418                b"\0",
1419            ],
1420        );
1421    }
1422
1423    #[test]
1424    fn label_count() {
1425        assert_eq!(Dname::root_ref().label_count(), 1);
1426        assert_eq!(
1427            Dname::from_slice(b"\x03www\x07example\x03com\0")
1428                .unwrap()
1429                .label_count(),
1430            4
1431        );
1432    }
1433
1434    #[test]
1435    fn first() {
1436        assert_eq!(Dname::root_ref().first().as_slice(), b"");
1437        assert_eq!(
1438            Dname::from_slice(b"\x03www\x07example\x03com\0")
1439                .unwrap()
1440                .first()
1441                .as_slice(),
1442            b"www"
1443        );
1444    }
1445
1446    #[test]
1447    fn last() {
1448        assert_eq!(Dname::root_ref().last().as_slice(), b"");
1449        assert_eq!(
1450            Dname::from_slice(b"\x03www\x07example\x03com\0")
1451                .unwrap()
1452                .last()
1453                .as_slice(),
1454            b""
1455        );
1456    }
1457
1458    #[test]
1459    fn starts_with() {
1460        let root = Dname::root_ref();
1461        let wecr =
1462            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1463                .unwrap();
1464
1465        assert!(root.starts_with(&root));
1466        assert!(wecr.starts_with(&wecr));
1467
1468        assert!(root.starts_with(&RelativeDname::empty_ref()));
1469        assert!(wecr.starts_with(&RelativeDname::empty_ref()));
1470
1471        let test = RelativeDname::from_slice(b"\x03www").unwrap();
1472        assert!(!root.starts_with(&test));
1473        assert!(wecr.starts_with(&test));
1474
1475        let test = RelativeDname::from_slice(b"\x03www\x07example").unwrap();
1476        assert!(!root.starts_with(&test));
1477        assert!(wecr.starts_with(&test));
1478
1479        let test =
1480            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
1481        assert!(!root.starts_with(&test));
1482        assert!(wecr.starts_with(&test));
1483
1484        let test = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
1485        assert!(!root.starts_with(&test));
1486        assert!(!wecr.starts_with(&test));
1487
1488        let test = RelativeDname::from_octets(b"\x03www".as_ref())
1489            .unwrap()
1490            .chain(
1491                RelativeDname::from_octets(b"\x07example".as_ref()).unwrap(),
1492            )
1493            .unwrap();
1494        assert!(!root.starts_with(&test));
1495        assert!(wecr.starts_with(&test));
1496
1497        let test = test
1498            .chain(RelativeDname::from_octets(b"\x03com".as_ref()).unwrap())
1499            .unwrap();
1500        assert!(!root.starts_with(&test));
1501        assert!(wecr.starts_with(&test));
1502    }
1503
1504    #[test]
1505    fn ends_with() {
1506        let root = Dname::root_ref();
1507        let wecr =
1508            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1509                .unwrap();
1510
1511        for name in wecr.iter_suffixes() {
1512            if name.is_root() {
1513                assert!(root.ends_with(&name));
1514            } else {
1515                assert!(!root.ends_with(&name));
1516            }
1517            assert!(wecr.ends_with(&name));
1518        }
1519    }
1520
1521    #[test]
1522    fn is_label_start() {
1523        let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1524
1525        assert!(wecr.is_label_start(0)); // \x03
1526        assert!(!wecr.is_label_start(1)); // w
1527        assert!(!wecr.is_label_start(2)); // w
1528        assert!(!wecr.is_label_start(3)); // w
1529        assert!(wecr.is_label_start(4)); // \x07
1530        assert!(!wecr.is_label_start(5)); // e
1531        assert!(!wecr.is_label_start(6)); // x
1532        assert!(!wecr.is_label_start(7)); // a
1533        assert!(!wecr.is_label_start(8)); // m
1534        assert!(!wecr.is_label_start(9)); // p
1535        assert!(!wecr.is_label_start(10)); // l
1536        assert!(!wecr.is_label_start(11)); // e
1537        assert!(wecr.is_label_start(12)); // \x03
1538        assert!(!wecr.is_label_start(13)); // c
1539        assert!(!wecr.is_label_start(14)); // o
1540        assert!(!wecr.is_label_start(15)); // m
1541        assert!(wecr.is_label_start(16)); // \0
1542        assert!(!wecr.is_label_start(17)); //
1543        assert!(!wecr.is_label_start(18)); //
1544    }
1545
1546    #[test]
1547    #[cfg(feature = "std")]
1548    fn slice() {
1549        let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1550
1551        assert_eq!(wecr.slice(..4).as_slice(), b"\x03www");
1552        assert_eq!(wecr.slice(..12).as_slice(), b"\x03www\x07example");
1553        assert_eq!(wecr.slice(4..12).as_slice(), b"\x07example");
1554        assert_eq!(wecr.slice(4..16).as_slice(), b"\x07example\x03com");
1555
1556        assert_panic!(wecr.slice(0..3));
1557        assert_panic!(wecr.slice(1..4));
1558        assert_panic!(wecr.slice(0..11));
1559        assert_panic!(wecr.slice(1..12));
1560        assert_panic!(wecr.slice(0..17));
1561        assert_panic!(wecr.slice(4..17));
1562        assert_panic!(wecr.slice(0..18));
1563    }
1564
1565    #[test]
1566    #[cfg(feature = "std")]
1567    fn slice_from() {
1568        let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1569
1570        assert_eq!(
1571            wecr.slice_from(0).as_slice(),
1572            b"\x03www\x07example\x03com\0"
1573        );
1574        assert_eq!(wecr.slice_from(4).as_slice(), b"\x07example\x03com\0");
1575        assert_eq!(wecr.slice_from(12).as_slice(), b"\x03com\0");
1576        assert_eq!(wecr.slice_from(16).as_slice(), b"\0");
1577
1578        assert_panic!(wecr.slice_from(17));
1579        assert_panic!(wecr.slice_from(18));
1580    }
1581
1582    #[test]
1583    #[cfg(feature = "std")]
1584    fn range() {
1585        let wecr =
1586            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1587                .unwrap();
1588
1589        assert_eq!(wecr.range(0..4).as_slice(), b"\x03www");
1590        assert_eq!(wecr.range(0..12).as_slice(), b"\x03www\x07example");
1591        assert_eq!(wecr.range(4..12).as_slice(), b"\x07example");
1592        assert_eq!(wecr.range(4..16).as_slice(), b"\x07example\x03com");
1593
1594        assert_panic!(wecr.range(0..3));
1595        assert_panic!(wecr.range(1..4));
1596        assert_panic!(wecr.range(0..11));
1597        assert_panic!(wecr.range(1..12));
1598        assert_panic!(wecr.range(0..17));
1599        assert_panic!(wecr.range(4..17));
1600        assert_panic!(wecr.range(0..18));
1601    }
1602
1603    #[test]
1604    #[cfg(feature = "std")]
1605    fn range_from() {
1606        let wecr =
1607            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1608                .unwrap();
1609
1610        assert_eq!(
1611            wecr.range_from(0).as_slice(),
1612            b"\x03www\x07example\x03com\0"
1613        );
1614        assert_eq!(wecr.range_from(4).as_slice(), b"\x07example\x03com\0");
1615        assert_eq!(wecr.range_from(12).as_slice(), b"\x03com\0");
1616        assert_eq!(wecr.range_from(16).as_slice(), b"\0");
1617
1618        assert_panic!(wecr.range_from(17));
1619        assert_panic!(wecr.range_from(18));
1620    }
1621
1622    #[test]
1623    #[cfg(feature = "std")]
1624    fn split() {
1625        let wecr =
1626            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1627                .unwrap();
1628
1629        let (left, right) = wecr.split(0);
1630        assert_eq!(left.as_slice(), b"");
1631        assert_eq!(right.as_slice(), b"\x03www\x07example\x03com\0");
1632
1633        let (left, right) = wecr.split(4);
1634        assert_eq!(left.as_slice(), b"\x03www");
1635        assert_eq!(right.as_slice(), b"\x07example\x03com\0");
1636
1637        let (left, right) = wecr.split(12);
1638        assert_eq!(left.as_slice(), b"\x03www\x07example");
1639        assert_eq!(right.as_slice(), b"\x03com\0");
1640
1641        let (left, right) = wecr.split(16);
1642        assert_eq!(left.as_slice(), b"\x03www\x07example\x03com");
1643        assert_eq!(right.as_slice(), b"\0");
1644
1645        assert_panic!(wecr.split(1));
1646        assert_panic!(wecr.split(14));
1647        assert_panic!(wecr.split(17));
1648        assert_panic!(wecr.split(18));
1649    }
1650
1651    #[test]
1652    #[cfg(feature = "std")]
1653    fn truncate() {
1654        let wecr =
1655            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1656                .unwrap();
1657
1658        assert_eq!(wecr.clone().truncate(0).as_slice(), b"");
1659        assert_eq!(wecr.clone().truncate(4).as_slice(), b"\x03www");
1660        assert_eq!(
1661            wecr.clone().truncate(12).as_slice(),
1662            b"\x03www\x07example"
1663        );
1664        assert_eq!(
1665            wecr.clone().truncate(16).as_slice(),
1666            b"\x03www\x07example\x03com"
1667        );
1668
1669        assert_panic!(wecr.clone().truncate(1));
1670        assert_panic!(wecr.clone().truncate(14));
1671        assert_panic!(wecr.clone().truncate(17));
1672        assert_panic!(wecr.clone().truncate(18));
1673    }
1674
1675    #[test]
1676    fn split_first() {
1677        let wecr =
1678            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1679                .unwrap();
1680
1681        let (label, wecr) = wecr.split_first().unwrap();
1682        assert_eq!(label, b"www".as_ref());
1683        assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
1684
1685        let (label, wecr) = wecr.split_first().unwrap();
1686        assert_eq!(label, b"example");
1687        assert_eq!(wecr.as_slice(), b"\x03com\0");
1688
1689        let (label, wecr) = wecr.split_first().unwrap();
1690        assert_eq!(label, b"com");
1691        assert_eq!(wecr.as_slice(), b"\0");
1692        assert!(wecr.split_first().is_none());
1693    }
1694
1695    #[test]
1696    fn parent() {
1697        let wecr =
1698            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1699                .unwrap();
1700
1701        let wecr = wecr.parent().unwrap();
1702        assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
1703        let wecr = wecr.parent().unwrap();
1704        assert_eq!(wecr.as_slice(), b"\x03com\0");
1705        let wecr = wecr.parent().unwrap();
1706        assert_eq!(wecr.as_slice(), b"\0");
1707        assert!(wecr.parent().is_none());
1708    }
1709
1710    #[test]
1711    fn strip_suffix() {
1712        let wecr =
1713            Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1714                .unwrap();
1715        let ecr =
1716            Dname::from_octets(b"\x07example\x03com\0".as_ref()).unwrap();
1717        let cr = Dname::from_octets(b"\x03com\0".as_ref()).unwrap();
1718        let wenr =
1719            Dname::from_octets(b"\x03www\x07example\x03net\0".as_ref())
1720                .unwrap();
1721        let enr =
1722            Dname::from_octets(b"\x07example\x03net\0".as_ref()).unwrap();
1723        let nr = Dname::from_octets(b"\x03net\0".as_ref()).unwrap();
1724
1725        assert_eq!(wecr.clone().strip_suffix(&wecr).unwrap().as_slice(), b"");
1726        assert_eq!(
1727            wecr.clone().strip_suffix(&ecr).unwrap().as_slice(),
1728            b"\x03www"
1729        );
1730        assert_eq!(
1731            wecr.clone().strip_suffix(&cr).unwrap().as_slice(),
1732            b"\x03www\x07example"
1733        );
1734        assert_eq!(
1735            wecr.clone()
1736                .strip_suffix(&Dname::root_slice())
1737                .unwrap()
1738                .as_slice(),
1739            b"\x03www\x07example\x03com"
1740        );
1741
1742        assert_eq!(
1743            wecr.clone().strip_suffix(&wenr).unwrap_err().as_slice(),
1744            b"\x03www\x07example\x03com\0"
1745        );
1746        assert_eq!(
1747            wecr.clone().strip_suffix(&enr).unwrap_err().as_slice(),
1748            b"\x03www\x07example\x03com\0"
1749        );
1750        assert_eq!(
1751            wecr.clone().strip_suffix(&nr).unwrap_err().as_slice(),
1752            b"\x03www\x07example\x03com\0"
1753        );
1754    }
1755
1756    #[test]
1757    #[cfg(feature = "std")]
1758    fn parse() {
1759        // Parse a correctly formatted name.
1760        let mut p = Parser::from_static(b"\x03www\x07example\x03com\0af");
1761        assert_eq!(
1762            Dname::parse(&mut p).unwrap().as_slice(),
1763            b"\x03www\x07example\x03com\0"
1764        );
1765        assert_eq!(p.peek_all(), b"af");
1766
1767        // Short buffer in middle of label.
1768        let mut p = Parser::from_static(b"\x03www\x07exam");
1769        assert_eq!(Dname::parse(&mut p), Err(ParseError::ShortInput));
1770
1771        // Short buffer at end of label.
1772        let mut p = Parser::from_static(b"\x03www\x07example");
1773        assert_eq!(Dname::parse(&mut p), Err(ParseError::ShortInput));
1774
1775        // Compressed name.
1776        let mut p = Parser::from_static(b"\x03com\x03www\x07example\xc0\0");
1777        p.advance(4).unwrap();
1778        assert_eq!(
1779            Dname::parse(&mut p),
1780            Err(DnameError::CompressedName.into())
1781        );
1782
1783        // Bad label header.
1784        let mut p = Parser::from_static(b"\x03www\x07example\xbffoo");
1785        assert!(Dname::parse(&mut p).is_err());
1786
1787        // Long name: 255 bytes is fine.
1788        let mut buf = Vec::new();
1789        for _ in 0..50 {
1790            buf.extend_from_slice(b"\x041234");
1791        }
1792        buf.extend_from_slice(b"\x03123\0");
1793        assert_eq!(buf.len(), 255);
1794        let mut p = Parser::from_ref(buf.as_slice());
1795        assert!(Dname::parse(&mut p).is_ok());
1796        assert_eq!(p.peek_all(), b"");
1797
1798        // Long name: 256 bytes are bad.
1799        let mut buf = Vec::new();
1800        for _ in 0..51 {
1801            buf.extend_from_slice(b"\x041234");
1802        }
1803        buf.extend_from_slice(b"\0");
1804        assert_eq!(buf.len(), 256);
1805        let mut p = Parser::from_ref(buf.as_slice());
1806        assert_eq!(Dname::parse(&mut p), Err(DnameError::LongName.into()));
1807    }
1808
1809    // I don’t think we need tests for `Compose::compose` since it only
1810    // copies the underlying bytes.
1811
1812    #[test]
1813    #[cfg(feature = "std")]
1814    fn compose_canonical() {
1815        use octseq::builder::infallible;
1816
1817        let mut buf = Vec::new();
1818        infallible(
1819            Dname::from_slice(b"\x03wWw\x07exaMPle\x03com\0")
1820                .unwrap()
1821                .compose_canonical(&mut buf),
1822        );
1823        assert_eq!(buf.as_slice(), b"\x03www\x07example\x03com\0");
1824    }
1825
1826    #[test]
1827    #[cfg(feature = "std")]
1828    fn from_str() {
1829        // Another simple test. `DnameBuilder` does all the heavy lifting,
1830        // so we don’t need to test all the escape sequence shenanigans here.
1831        // Just check that we’ll always get a name, final dot or not, unless
1832        // the string is empty.
1833        use core::str::FromStr;
1834        use std::vec::Vec;
1835
1836        assert_eq!(
1837            Dname::<Vec<u8>>::from_str(".").unwrap().as_slice(),
1838            b"\0"
1839        );
1840        assert_eq!(
1841            Dname::<Vec<u8>>::from_str("www.example.com")
1842                .unwrap()
1843                .as_slice(),
1844            b"\x03www\x07example\x03com\0"
1845        );
1846        assert_eq!(
1847            Dname::<Vec<u8>>::from_str("www.example.com.")
1848                .unwrap()
1849                .as_slice(),
1850            b"\x03www\x07example\x03com\0"
1851        );
1852    }
1853
1854    #[test]
1855    fn eq() {
1856        assert_eq!(
1857            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1858            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
1859        );
1860        assert_eq!(
1861            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1862            Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap()
1863        );
1864        assert_eq!(
1865            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1866            &RelativeDname::from_octets(b"\x03www".as_ref())
1867                .unwrap()
1868                .chain(
1869                    RelativeDname::from_octets(
1870                        b"\x07example\x03com".as_ref()
1871                    )
1872                    .unwrap()
1873                )
1874                .unwrap()
1875                .chain(Dname::root_ref())
1876                .unwrap()
1877        );
1878        assert_eq!(
1879            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1880            &RelativeDname::from_octets(b"\x03wWw".as_ref())
1881                .unwrap()
1882                .chain(
1883                    RelativeDname::from_octets(
1884                        b"\x07eXAMple\x03coM".as_ref()
1885                    )
1886                    .unwrap()
1887                )
1888                .unwrap()
1889                .chain(Dname::root_ref())
1890                .unwrap()
1891        );
1892        assert_ne!(
1893            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1894            Dname::from_slice(b"\x03ww4\x07example\x03com\0").unwrap()
1895        );
1896        assert_ne!(
1897            Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1898            &RelativeDname::from_octets(b"\x03www".as_ref())
1899                .unwrap()
1900                .chain(
1901                    RelativeDname::from_octets(
1902                        b"\x073xample\x03com".as_ref()
1903                    )
1904                    .unwrap()
1905                )
1906                .unwrap()
1907                .chain(Dname::root_ref())
1908                .unwrap()
1909        );
1910    }
1911
1912    #[test]
1913    fn cmp() {
1914        use core::cmp::Ordering;
1915
1916        // The following is taken from section 6.1 of RFC 4034.
1917        let names = [
1918            Dname::from_slice(b"\x07example\0").unwrap(),
1919            Dname::from_slice(b"\x01a\x07example\0").unwrap(),
1920            Dname::from_slice(b"\x08yljkjljk\x01a\x07example\0").unwrap(),
1921            Dname::from_slice(b"\x01Z\x01a\x07example\0").unwrap(),
1922            Dname::from_slice(b"\x04zABC\x01a\x07example\0").unwrap(),
1923            Dname::from_slice(b"\x01z\x07example\0").unwrap(),
1924            Dname::from_slice(b"\x01\x01\x01z\x07example\0").unwrap(),
1925            Dname::from_slice(b"\x01*\x01z\x07example\0").unwrap(),
1926            Dname::from_slice(b"\x01\xc8\x01z\x07example\0").unwrap(),
1927        ];
1928        for i in 0..names.len() {
1929            for j in 0..names.len() {
1930                let ord = i.cmp(&j);
1931                assert_eq!(names[i].partial_cmp(names[j]), Some(ord));
1932                assert_eq!(names[i].cmp(names[j]), ord);
1933            }
1934        }
1935
1936        let n1 = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1937        let n2 = Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap();
1938        assert_eq!(n1.partial_cmp(n2), Some(Ordering::Equal));
1939        assert_eq!(n1.cmp(n2), Ordering::Equal);
1940    }
1941
1942    #[test]
1943    #[cfg(feature = "std")]
1944    fn hash() {
1945        use std::collections::hash_map::DefaultHasher;
1946        use std::hash::{Hash, Hasher};
1947
1948        let mut s1 = DefaultHasher::new();
1949        let mut s2 = DefaultHasher::new();
1950        Dname::from_slice(b"\x03www\x07example\x03com\0")
1951            .unwrap()
1952            .hash(&mut s1);
1953        Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0")
1954            .unwrap()
1955            .hash(&mut s2);
1956        assert_eq!(s1.finish(), s2.finish());
1957    }
1958
1959    // Scan and Display skipped for now.
1960
1961    #[cfg(all(feature = "serde", feature = "std"))]
1962    #[test]
1963    fn ser_de() {
1964        use serde_test::{assert_tokens, Configure, Token};
1965
1966        let name = Dname::<Vec<u8>>::from_str("www.example.com.").unwrap();
1967        assert_tokens(
1968            &name.clone().compact(),
1969            &[
1970                Token::NewtypeStruct { name: "Dname" },
1971                Token::ByteBuf(b"\x03www\x07example\x03com\0"),
1972            ],
1973        );
1974        assert_tokens(
1975            &name.readable(),
1976            &[
1977                Token::NewtypeStruct { name: "Dname" },
1978                Token::Str("www.example.com"),
1979            ],
1980        );
1981        assert_tokens(
1982            &Dname::root_vec().readable(),
1983            &[Token::NewtypeStruct { name: "Dname" }, Token::Str(".")],
1984        );
1985    }
1986}