domain/base/name/
relative.rs

1//! Uncompressed, relative domain names.
2//!
3//! This is a private module. Its public types are re-exported by the parent.
4
5use super::super::wire::ParseError;
6use super::builder::{DnameBuilder, FromStrError, PushError};
7use super::chain::{Chain, LongChainError};
8use super::dname::Dname;
9use super::label::{Label, LabelTypeError, SplitLabelError};
10use super::traits::{ToLabelIter, ToRelativeDname};
11#[cfg(feature = "bytes")]
12use bytes::Bytes;
13use core::cmp::Ordering;
14use core::ops::{Bound, RangeBounds};
15use core::str::FromStr;
16use core::{cmp, fmt, hash};
17use octseq::builder::{
18    EmptyBuilder, FreezeBuilder, FromBuilder, IntoBuilder, Truncate,
19};
20use octseq::octets::{Octets, OctetsFrom};
21#[cfg(feature = "serde")]
22use octseq::serde::{DeserializeOctets, SerializeOctets};
23#[cfg(feature = "std")]
24use std::vec::Vec;
25
26//------------ RelativeDname -------------------------------------------------
27
28/// An uncompressed, relative domain name.
29///
30/// A relative domain name is one that doesn’t end with the root label. As the
31/// name suggests, it is relative to some other domain name. This type wraps
32/// a octets sequence containing such a relative name similarly to the way
33/// [`Dname`] wraps an absolute one. In fact, it behaves very similarly to
34/// [`Dname`] taking into account differences when slicing and dicing names.
35///
36/// `RelativeDname` guarantees that the name is at most 254 bytes long. As the
37/// length limit for a domain name is actually 255 bytes, this means that you
38/// can always safely turn a `RelativeDname` into a `Dname` by adding the root
39/// label (which is exactly one byte long).
40///
41/// [`Bytes`]: ../../../bytes/struct.Bytes.html
42/// [`Dname`]: struct.Dname.html
43#[derive(Clone)]
44pub struct RelativeDname<Octs: ?Sized>(Octs);
45
46/// # Creating Values
47///
48impl<Octs> RelativeDname<Octs> {
49    /// Creates a relative domain name from octets without checking.
50    ///
51    /// Since the content of the octets sequence can be anything, really,
52    /// this is an unsafe function.
53    ///
54    /// # Safety
55    ///
56    /// The octets sequence passed via `octets` must contain a correctly
57    /// encoded relative domain name. It must be at most 254 octets long.
58    /// There must be no root labels anywhere in the name.
59    pub const unsafe fn from_octets_unchecked(octets: Octs) -> Self {
60        RelativeDname(octets)
61    }
62
63    /// Creates a relative domain name from an octets sequence.
64    ///
65    /// This checks that `octets` contains a properly encoded relative domain
66    /// name and fails if it doesn’t.
67    pub fn from_octets(octets: Octs) -> Result<Self, RelativeDnameError>
68    where
69        Octs: AsRef<[u8]>,
70    {
71        RelativeDname::check_slice(octets.as_ref())?;
72        Ok(unsafe { RelativeDname::from_octets_unchecked(octets) })
73    }
74
75    /// Creates an empty relative domain name.
76    #[must_use]
77    pub fn empty() -> Self
78    where
79        Octs: From<&'static [u8]>,
80    {
81        unsafe { RelativeDname::from_octets_unchecked(b"".as_ref().into()) }
82    }
83
84    /// Creates a relative domain name representing the wildcard label.
85    ///
86    /// The wildcard label is intended to match any label. There are special
87    /// rules for names with wildcard labels. Note that the comparison traits
88    /// implemented for domain names do *not* consider wildcards and treat
89    /// them as regular labels.
90    #[must_use]
91    pub fn wildcard() -> Self
92    where
93        Octs: From<&'static [u8]>,
94    {
95        unsafe {
96            RelativeDname::from_octets_unchecked(b"\x01*".as_ref().into())
97        }
98    }
99
100    /// Creates a domain name from a sequence of characters.
101    ///
102    /// The sequence must result in a domain name in representation format.
103    /// That is, its labels should be separated by dots.
104    /// Actual dots, white space and backslashes should be escaped by a
105    /// preceeding backslash, and any byte value that is not a printable
106    /// ASCII character should be encoded by a backslash followed by its
107    /// three digit decimal value.
108    ///
109    /// If Internationalized Domain Names are to be used, the labels already
110    /// need to be in punycode-encoded form.
111    pub fn from_chars<C>(chars: C) -> Result<Self, RelativeFromStrError>
112    where
113        Octs: FromBuilder,
114        <Octs as FromBuilder>::Builder: EmptyBuilder
115            + FreezeBuilder<Octets = Octs>
116            + AsRef<[u8]>
117            + AsMut<[u8]>,
118        C: IntoIterator<Item = char>,
119    {
120        let mut builder = DnameBuilder::<Octs::Builder>::new();
121        builder.append_chars(chars)?;
122        if builder.in_label() || builder.is_empty() {
123            Ok(builder.finish())
124        } else {
125            Err(RelativeFromStrError::AbsoluteName)
126        }
127    }
128}
129
130impl RelativeDname<[u8]> {
131    /// Creates a domain name from an octet slice without checking.
132    ///
133    /// # Safety
134    ///
135    /// The same rules as for `from_octets_unchecked` apply.
136    pub(super) unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
137        &*(slice as *const [u8] as *const RelativeDname<[u8]>)
138    }
139
140    /// Creates a relative domain name from an octet slice.
141    ///
142    /// Note that the input must be in wire format, as shown below.
143    ///
144    /// # Example
145    ///
146    /// ```
147    /// use domain::base::name::RelativeDname;
148    /// RelativeDname::from_slice(b"\x0c_submissions\x04_tcp");
149    /// ```
150    pub fn from_slice(slice: &[u8]) -> Result<&Self, RelativeDnameError> {
151        Self::check_slice(slice)?;
152        Ok(unsafe { Self::from_slice_unchecked(slice) })
153    }
154
155    /// Returns an empty relative name atop a unsized slice.
156    #[must_use]
157    pub fn empty_slice() -> &'static Self {
158        unsafe { Self::from_slice_unchecked(b"") }
159    }
160
161    #[must_use]
162    pub fn wildcard_slice() -> &'static Self {
163        unsafe { Self::from_slice_unchecked(b"\x01*") }
164    }
165
166    /// Checks whether an octet slice contains a correctly encoded name.
167    pub(super) fn check_slice(
168        mut slice: &[u8],
169    ) -> Result<(), RelativeDnameError> {
170        if slice.len() > 254 {
171            return Err(RelativeDnameError::LongName);
172        }
173        while !slice.is_empty() {
174            let (label, tail) = Label::split_from(slice)?;
175            if label.is_root() {
176                return Err(RelativeDnameError::AbsoluteName);
177            }
178            slice = tail;
179        }
180        Ok(())
181    }
182}
183
184impl RelativeDname<&'static [u8]> {
185    /// Creates an empty relative name atop a slice reference.
186    #[must_use]
187    pub fn empty_ref() -> Self {
188        Self::empty()
189    }
190
191    /// Creates a wildcard relative name atop a slice reference.
192    #[must_use]
193    pub fn wildcard_ref() -> Self {
194        Self::wildcard()
195    }
196}
197
198#[cfg(feature = "std")]
199impl RelativeDname<Vec<u8>> {
200    /// Creates an empty relative name atop a `Vec<u8>`.
201    #[must_use]
202    pub fn empty_vec() -> Self {
203        Self::empty()
204    }
205
206    /// Creates a wildcard relative name atop a `Vec<u8>`.
207    #[must_use]
208    pub fn wildcard_vec() -> Self {
209        Self::wildcard()
210    }
211
212    /// Parses a string into a relative name atop a `Vec<u8>`.
213    pub fn vec_from_str(s: &str) -> Result<Self, RelativeFromStrError> {
214        FromStr::from_str(s)
215    }
216}
217
218#[cfg(feature = "bytes")]
219impl RelativeDname<Bytes> {
220    /// Creates an empty relative name atop a bytes value.
221    pub fn empty_bytes() -> Self {
222        Self::empty()
223    }
224
225    /// Creates a wildcard relative name atop a bytes value.
226    pub fn wildcard_bytes() -> Self {
227        Self::wildcard()
228    }
229
230    /// Parses a string into a relative name atop a `Bytes`.
231    pub fn bytes_from_str(s: &str) -> Result<Self, RelativeFromStrError> {
232        FromStr::from_str(s)
233    }
234}
235
236/// # Conversions
237///
238impl<Octs: ?Sized> RelativeDname<Octs> {
239    /// Returns a reference to the underlying octets.
240    pub fn as_octets(&self) -> &Octs {
241        &self.0
242    }
243
244    /// Converts the name into the underlying octets.
245    pub fn into_octets(self) -> Octs
246    where
247        Octs: Sized,
248    {
249        self.0
250    }
251
252    /// Returns a domain name using a reference to the octets.
253    pub fn for_ref(&self) -> RelativeDname<&Octs> {
254        unsafe { RelativeDname::from_octets_unchecked(&self.0) }
255    }
256
257    /// Returns a reference to an octets slice with the content of the name.
258    pub fn as_slice(&self) -> &[u8]
259    where
260        Octs: AsRef<[u8]>,
261    {
262        self.0.as_ref()
263    }
264
265    /// Returns a domain name for the octets slice of the content.
266    pub fn for_slice(&self) -> &RelativeDname<[u8]>
267    where
268        Octs: AsRef<[u8]>,
269    {
270        unsafe { RelativeDname::from_slice_unchecked(self.0.as_ref()) }
271    }
272
273    /// Converts the name into its canonical form.
274    pub fn make_canonical(&mut self)
275    where
276        Octs: AsMut<[u8]>,
277    {
278        Label::make_slice_canonical(self.0.as_mut());
279    }
280}
281
282impl<Octs> RelativeDname<Octs> {
283    /// Converts the name into a domain name builder for appending data.
284    ///
285    /// This method is only available for octets sequences that have an
286    /// associated octets builder such as `Vec<u8>` or `Bytes`.
287    pub fn into_builder(self) -> DnameBuilder<<Octs as IntoBuilder>::Builder>
288    where
289        Octs: IntoBuilder,
290    {
291        unsafe { DnameBuilder::from_builder_unchecked(self.0.into_builder()) }
292    }
293
294    /// Converts the name into an absolute name by appending the root label.
295    ///
296    /// This manipulates the name itself and thus is only available for
297    /// octets sequences that can be converted into an octets builder and back
298    /// such as `Vec<u8>`.
299    ///
300    /// [`chain_root`]: #method.chain_root
301    pub fn into_absolute(self) -> Result<Dname<Octs>, PushError>
302    where
303        Octs: IntoBuilder,
304        <Octs as IntoBuilder>::Builder:
305            FreezeBuilder<Octets = Octs> + AsRef<[u8]> + AsMut<[u8]>,
306    {
307        self.into_builder().into_dname()
308    }
309
310    /// Chains another name to the end of this name.
311    ///
312    /// Depending on whether `other` is an absolute or relative domain name,
313    /// the resulting name will behave like an absolute or relative name.
314    ///
315    /// The method will fail if the combined length of the two names is
316    /// greater than the size limit of 255. Note that in this case you will
317    /// loose both `self` and `other`, so it might be worthwhile to check
318    /// first.
319    pub fn chain<N: ToLabelIter>(
320        self,
321        other: N,
322    ) -> Result<Chain<Self, N>, LongChainError>
323    where
324        Octs: AsRef<[u8]>,
325    {
326        Chain::new(self, other)
327    }
328
329    /// Creates an absolute name by chaining the root label to it.
330    pub fn chain_root(self) -> Chain<Self, Dname<&'static [u8]>>
331    where
332        Octs: AsRef<[u8]>,
333    {
334        self.chain(Dname::root()).unwrap()
335    }
336}
337
338/// # Properties
339///
340impl<Octs: AsRef<[u8]> + ?Sized> RelativeDname<Octs> {
341    /// Returns the length of the name.
342    pub fn len(&self) -> usize {
343        self.0.as_ref().len()
344    }
345
346    /// Returns whether the name is empty.
347    pub fn is_empty(&self) -> bool {
348        self.0.as_ref().is_empty()
349    }
350}
351
352/// # Working with Labels
353///
354impl<Octs: AsRef<[u8]> + ?Sized> RelativeDname<Octs> {
355    /// Returns an iterator over the labels of the domain name.
356    pub fn iter(&self) -> DnameIter {
357        DnameIter::new(self.0.as_ref())
358    }
359
360    /// Returns the number of labels in the name.
361    pub fn label_count(&self) -> usize {
362        self.iter().count()
363    }
364
365    /// Returns a reference to the first label if the name isn’t empty.
366    pub fn first(&self) -> Option<&Label> {
367        self.iter().next()
368    }
369
370    /// Returns a reference to the last label if the name isn’t empty.
371    pub fn last(&self) -> Option<&Label> {
372        self.iter().next_back()
373    }
374
375    /// Returns the number of dots in the string representation of the name.
376    ///
377    /// Specifically, returns a value equal to the number of labels minus one,
378    /// except for an empty name where it returns a zero, also.
379    pub fn ndots(&self) -> usize {
380        if self.0.as_ref().is_empty() {
381            0
382        } else {
383            self.label_count() - 1
384        }
385    }
386
387    /// Determines whether `base` is a prefix of `self`.
388    pub fn starts_with<N: ToLabelIter>(&self, base: &N) -> bool {
389        <Self as ToLabelIter>::starts_with(self, base)
390    }
391
392    /// Determines whether `base` is a suffix of `self`.
393    pub fn ends_with<N: ToLabelIter>(&self, base: &N) -> bool {
394        <Self as ToLabelIter>::ends_with(self, base)
395    }
396
397    /// Returns whether an index points to the first octet of a label.
398    pub fn is_label_start(&self, mut index: usize) -> bool {
399        if index == 0 {
400            return true;
401        }
402        let mut tmp = self.as_slice();
403        while !tmp.is_empty() {
404            let (label, tail) = Label::split_from(tmp).unwrap();
405            let len = label.len() + 1;
406            match index.cmp(&len) {
407                Ordering::Less => return false,
408                Ordering::Equal => return true,
409                _ => {}
410            }
411            index -= len;
412            tmp = tail;
413        }
414        false
415    }
416
417    /// Like `is_label_start` but panics if it isn’t.
418    fn check_index(&self, index: usize) {
419        if !self.is_label_start(index) {
420            panic!("index not at start of a label");
421        }
422    }
423
424    fn check_bounds(&self, bounds: &impl RangeBounds<usize>) {
425        match bounds.start_bound().cloned() {
426            Bound::Included(idx) => self.check_index(idx),
427            Bound::Excluded(_) => {
428                panic!("excluded lower bounds not supported");
429            }
430            Bound::Unbounded => {}
431        }
432        match bounds.end_bound().cloned() {
433            Bound::Included(idx) => self
434                .check_index(idx.checked_add(1).expect("end bound too big")),
435            Bound::Excluded(idx) => self.check_index(idx),
436            Bound::Unbounded => {}
437        }
438    }
439
440    /// Returns a part of the name indicated by start and end positions.
441    ///
442    /// The returned name will start at position `begin` and end right before
443    /// position `end`. Both positions are given as indexes into the
444    /// underlying octets sequence and must point to the begining of a label.
445    ///
446    /// The method returns a reference to an unsized relative domain name and
447    /// is thus best suited for temporary referencing. If you want to keep the
448    /// part of the name around, [`range`] is likely a better choice.
449    ///
450    /// # Panics
451    ///
452    /// The method panics if either position is not the beginning of a label
453    /// or is out of bounds.
454    ///
455    /// [`range`]: #method.range
456    pub fn slice(
457        &self,
458        range: impl RangeBounds<usize>,
459    ) -> &RelativeDname<[u8]> {
460        self.check_bounds(&range);
461        unsafe {
462            RelativeDname::from_slice_unchecked(self.0.as_ref().range(range))
463        }
464    }
465
466    /// Returns a part of the name indicated by start and end positions.
467    ///
468    /// The returned name will start at position `begin` and end right before
469    /// position `end`. Both positions are given as indexes into the
470    /// underlying octets sequence and must point to the begining of a label.
471    ///
472    /// # Panics
473    ///
474    /// The method panics if either position is not the beginning of a label
475    /// or is out of bounds.
476    pub fn range(
477        &self,
478        range: impl RangeBounds<usize>,
479    ) -> RelativeDname<<Octs as Octets>::Range<'_>>
480    where
481        Octs: Octets,
482    {
483        self.check_bounds(&range);
484        unsafe { RelativeDname::from_octets_unchecked(self.0.range(range)) }
485    }
486}
487
488impl<Octs: AsRef<[u8]> + ?Sized> RelativeDname<Octs> {
489    /// Splits the name into two at the given position.
490    ///
491    /// Returns a pair of the left and right part of the split name.
492    ///
493    /// # Panics
494    ///
495    /// The method panics if the position is not the beginning of a label
496    /// or is beyond the end of the name.
497    pub fn split(
498        &self,
499        mid: usize,
500    ) -> (
501        RelativeDname<Octs::Range<'_>>,
502        RelativeDname<Octs::Range<'_>>,
503    )
504    where
505        Octs: Octets,
506    {
507        self.check_index(mid);
508        unsafe {
509            (
510                RelativeDname::from_octets_unchecked(self.0.range(..mid)),
511                RelativeDname::from_octets_unchecked(self.0.range(mid..)),
512            )
513        }
514    }
515
516    /// Truncates the name to the given length.
517    ///
518    /// # Panics
519    ///
520    /// The method panics if the position is not the beginning of a label
521    /// or is beyond the end of the name.
522    pub fn truncate(&mut self, len: usize)
523    where
524        Octs: Truncate,
525    {
526        self.check_index(len);
527        self.0.truncate(len);
528    }
529
530    /// Splits off the first label.
531    ///
532    /// If there is at least one label in the name, returns the first label
533    /// as a relative domain name with exactly one label and makes `self`
534    /// contain the domain name starting after that first label. If the name
535    /// is empty, returns `None`.
536    pub fn split_first(
537        &self,
538    ) -> Option<(&Label, RelativeDname<Octs::Range<'_>>)>
539    where
540        Octs: Octets,
541    {
542        if self.is_empty() {
543            return None;
544        }
545        let label = self.iter().next()?;
546        Some((label, self.split(label.len() + 1).1))
547    }
548
549    /// Returns the parent name.
550    ///
551    /// Returns `None` if the name was empty.
552    pub fn parent(&self) -> Option<RelativeDname<Octs::Range<'_>>>
553    where
554        Octs: Octets,
555    {
556        self.split_first().map(|(_, parent)| parent)
557    }
558
559    /// Strips the suffix `base` from the domain name.
560    ///
561    /// This will fail if `base` isn’t actually a suffix, i.e., if
562    /// [`ends_with`] doesn’t return `true`.
563    ///
564    /// [`ends_with`]: #method.ends_with
565    pub fn strip_suffix<N: ToRelativeDname>(
566        &mut self,
567        base: &N,
568    ) -> Result<(), StripSuffixError>
569    where
570        Octs: Truncate,
571    {
572        if self.ends_with(base) {
573            let idx = self.0.as_ref().len() - usize::from(base.compose_len());
574            self.0.truncate(idx);
575            Ok(())
576        } else {
577            Err(StripSuffixError)
578        }
579    }
580}
581
582//--- AsRef
583
584impl<Octs> AsRef<Octs> for RelativeDname<Octs> {
585    fn as_ref(&self) -> &Octs {
586        &self.0
587    }
588}
589
590impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for RelativeDname<Octs> {
591    fn as_ref(&self) -> &[u8] {
592        self.0.as_ref()
593    }
594}
595
596//--- OctetsFrom
597
598impl<Octs, SrcOcts> OctetsFrom<RelativeDname<SrcOcts>> for RelativeDname<Octs>
599where
600    Octs: OctetsFrom<SrcOcts>,
601{
602    type Error = Octs::Error;
603
604    fn try_octets_from(
605        source: RelativeDname<SrcOcts>,
606    ) -> Result<Self, Self::Error> {
607        Octs::try_octets_from(source.0)
608            .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
609    }
610}
611
612//--- FromStr
613
614impl<Octs> FromStr for RelativeDname<Octs>
615where
616    Octs: FromBuilder,
617    <Octs as FromBuilder>::Builder: EmptyBuilder
618        + FreezeBuilder<Octets = Octs>
619        + AsRef<[u8]>
620        + AsMut<[u8]>,
621{
622    type Err = RelativeFromStrError;
623
624    /// Parses a string into an absolute domain name.
625    ///
626    /// The name needs to be formatted in representation format, i.e., as a
627    /// sequence of labels separated by dots. If Internationalized Domain
628    /// Name (IDN) labels are to be used, these need to be given in punycode
629    /// encoded form.
630    ///
631    /// This implementation will error if the name ends in a dot since that
632    /// indicates an absolute name.
633    fn from_str(s: &str) -> Result<Self, Self::Err> {
634        Self::from_chars(s.chars())
635    }
636}
637
638//--- ToLabelIter and ToRelativeDname
639
640impl<Octs> ToLabelIter for RelativeDname<Octs>
641where
642    Octs: AsRef<[u8]> + ?Sized,
643{
644    type LabelIter<'a> = DnameIter<'a> where Octs: 'a;
645
646    fn iter_labels(&self) -> Self::LabelIter<'_> {
647        self.iter()
648    }
649
650    fn compose_len(&self) -> u16 {
651        u16::try_from(self.0.as_ref().len()).expect("long domain name")
652    }
653}
654
655impl<Octs: AsRef<[u8]> + ?Sized> ToRelativeDname for RelativeDname<Octs> {
656    fn as_flat_slice(&self) -> Option<&[u8]> {
657        Some(self.0.as_ref())
658    }
659
660    fn is_empty(&self) -> bool {
661        self.0.as_ref().is_empty()
662    }
663}
664
665//--- IntoIterator
666
667impl<'a, Octs> IntoIterator for &'a RelativeDname<Octs>
668where
669    Octs: AsRef<[u8]> + ?Sized,
670{
671    type Item = &'a Label;
672    type IntoIter = DnameIter<'a>;
673
674    fn into_iter(self) -> Self::IntoIter {
675        self.iter()
676    }
677}
678
679//--- PartialEq and Eq
680
681impl<Octs, N> PartialEq<N> for RelativeDname<Octs>
682where
683    Octs: AsRef<[u8]> + ?Sized,
684    N: ToRelativeDname + ?Sized,
685{
686    fn eq(&self, other: &N) -> bool {
687        self.name_eq(other)
688    }
689}
690
691impl<Octs: AsRef<[u8]> + ?Sized> Eq for RelativeDname<Octs> {}
692
693//--- PartialOrd and Ord
694
695impl<Octs, N> PartialOrd<N> for RelativeDname<Octs>
696where
697    Octs: AsRef<[u8]> + ?Sized,
698    N: ToRelativeDname + ?Sized,
699{
700    fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
701        Some(self.name_cmp(other))
702    }
703}
704
705impl<Octs: AsRef<[u8]> + ?Sized> Ord for RelativeDname<Octs> {
706    fn cmp(&self, other: &Self) -> cmp::Ordering {
707        self.name_cmp(other)
708    }
709}
710
711//--- Hash
712
713impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for RelativeDname<Octs> {
714    fn hash<H: hash::Hasher>(&self, state: &mut H) {
715        for item in self.iter() {
716            item.hash(state)
717        }
718    }
719}
720
721//--- Display and Debug
722
723impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for RelativeDname<Octs> {
724    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
725        let mut iter = self.iter();
726        match iter.next() {
727            Some(label) => label.fmt(f)?,
728            None => return Ok(()),
729        }
730        for label in iter {
731            f.write_str(".")?;
732            label.fmt(f)?;
733        }
734        Ok(())
735    }
736}
737
738impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for RelativeDname<Octs> {
739    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
740        write!(f, "RelativeDname({})", self)
741    }
742}
743
744//--- Serialize and Deserialize
745
746#[cfg(feature = "serde")]
747impl<Octs> serde::Serialize for RelativeDname<Octs>
748where
749    Octs: AsRef<[u8]> + SerializeOctets + ?Sized,
750{
751    fn serialize<S: serde::Serializer>(
752        &self,
753        serializer: S,
754    ) -> Result<S::Ok, S::Error> {
755        if serializer.is_human_readable() {
756            serializer.serialize_newtype_struct(
757                "RelativeDname",
758                &format_args!("{}", self),
759            )
760        } else {
761            serializer.serialize_newtype_struct(
762                "RelativeDname",
763                &self.0.as_serialized_octets(),
764            )
765        }
766    }
767}
768
769#[cfg(feature = "serde")]
770impl<'de, Octs> serde::Deserialize<'de> for RelativeDname<Octs>
771where
772    Octs: FromBuilder + DeserializeOctets<'de>,
773    <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
774        + EmptyBuilder
775        + AsRef<[u8]>
776        + AsMut<[u8]>,
777{
778    fn deserialize<D: serde::Deserializer<'de>>(
779        deserializer: D,
780    ) -> Result<Self, D::Error> {
781        use core::marker::PhantomData;
782
783        struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
784
785        impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
786        where
787            Octs: FromBuilder + DeserializeOctets<'de>,
788            <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
789                + EmptyBuilder
790                + AsRef<[u8]>
791                + AsMut<[u8]>,
792        {
793            type Value = RelativeDname<Octs>;
794
795            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
796                f.write_str("a relative domain name")
797            }
798
799            fn visit_str<E: serde::de::Error>(
800                self,
801                v: &str,
802            ) -> Result<Self::Value, E> {
803                let mut builder = DnameBuilder::<Octs::Builder>::new();
804                builder.append_chars(v.chars()).map_err(E::custom)?;
805                Ok(builder.finish())
806            }
807
808            fn visit_borrowed_bytes<E: serde::de::Error>(
809                self,
810                value: &'de [u8],
811            ) -> Result<Self::Value, E> {
812                self.0.visit_borrowed_bytes(value).and_then(|octets| {
813                    RelativeDname::from_octets(octets).map_err(E::custom)
814                })
815            }
816
817            #[cfg(feature = "std")]
818            fn visit_byte_buf<E: serde::de::Error>(
819                self,
820                value: std::vec::Vec<u8>,
821            ) -> Result<Self::Value, E> {
822                self.0.visit_byte_buf(value).and_then(|octets| {
823                    RelativeDname::from_octets(octets).map_err(E::custom)
824                })
825            }
826        }
827
828        struct NewtypeVisitor<T>(PhantomData<T>);
829
830        impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
831        where
832            Octs: FromBuilder + DeserializeOctets<'de>,
833            <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
834                + EmptyBuilder
835                + AsRef<[u8]>
836                + AsMut<[u8]>,
837        {
838            type Value = RelativeDname<Octs>;
839
840            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
841                f.write_str("a relative domain name")
842            }
843
844            fn visit_newtype_struct<D: serde::Deserializer<'de>>(
845                self,
846                deserializer: D,
847            ) -> Result<Self::Value, D::Error> {
848                if deserializer.is_human_readable() {
849                    deserializer
850                        .deserialize_str(InnerVisitor(Octs::visitor()))
851                } else {
852                    Octs::deserialize_with_visitor(
853                        deserializer,
854                        InnerVisitor(Octs::visitor()),
855                    )
856                }
857            }
858        }
859
860        deserializer.deserialize_newtype_struct(
861            "RelativeDname",
862            NewtypeVisitor(PhantomData),
863        )
864    }
865}
866
867//------------ DnameIter -----------------------------------------------------
868
869/// An iterator over the labels in an uncompressed name.
870#[derive(Clone, Debug)]
871pub struct DnameIter<'a> {
872    slice: &'a [u8],
873}
874
875impl<'a> DnameIter<'a> {
876    pub(super) fn new(slice: &'a [u8]) -> Self {
877        DnameIter { slice }
878    }
879}
880
881impl<'a> Iterator for DnameIter<'a> {
882    type Item = &'a Label;
883
884    fn next(&mut self) -> Option<Self::Item> {
885        let (label, tail) = match Label::split_from(self.slice) {
886            Ok(res) => res,
887            Err(_) => return None,
888        };
889        self.slice = tail;
890        Some(label)
891    }
892}
893
894impl<'a> DoubleEndedIterator for DnameIter<'a> {
895    fn next_back(&mut self) -> Option<Self::Item> {
896        if self.slice.is_empty() {
897            return None;
898        }
899        let mut tmp = self.slice;
900        loop {
901            let (label, tail) = Label::split_from(tmp).unwrap();
902            if tail.is_empty() {
903                let end = self.slice.len() - (label.len() + 1);
904                self.slice = &self.slice[..end];
905                return Some(label);
906            } else {
907                tmp = tail
908            }
909        }
910    }
911}
912
913//============ Error Types ===================================================
914
915//------------ RelativeDnameError --------------------------------------------
916
917/// An error happened while creating a domain name from octets.
918#[derive(Clone, Copy, Debug, Eq, PartialEq)]
919pub enum RelativeDnameError {
920    /// A bad label was encountered.
921    BadLabel(LabelTypeError),
922
923    /// A compressed name was encountered.
924    CompressedName,
925
926    /// The data ended before the end of a label.
927    ShortInput,
928
929    /// The domain name was longer than 255 octets.
930    LongName,
931
932    /// The root label was encountered.
933    AbsoluteName,
934}
935
936//--- From
937
938impl From<LabelTypeError> for RelativeDnameError {
939    fn from(err: LabelTypeError) -> Self {
940        RelativeDnameError::BadLabel(err)
941    }
942}
943
944impl From<SplitLabelError> for RelativeDnameError {
945    fn from(err: SplitLabelError) -> Self {
946        match err {
947            SplitLabelError::Pointer(_) => RelativeDnameError::CompressedName,
948            SplitLabelError::BadType(t) => RelativeDnameError::BadLabel(t),
949            SplitLabelError::ShortInput => RelativeDnameError::ShortInput,
950        }
951    }
952}
953
954//--- Display and Error
955
956impl fmt::Display for RelativeDnameError {
957    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
958        match *self {
959            RelativeDnameError::BadLabel(err) => err.fmt(f),
960            RelativeDnameError::CompressedName => {
961                f.write_str("compressed domain name")
962            }
963            RelativeDnameError::ShortInput => ParseError::ShortInput.fmt(f),
964            RelativeDnameError::LongName => f.write_str("long domain name"),
965            RelativeDnameError::AbsoluteName => {
966                f.write_str("absolute domain name")
967            }
968        }
969    }
970}
971
972#[cfg(feature = "std")]
973impl std::error::Error for RelativeDnameError {}
974
975//------------ RelativeFromStrError ------------------------------------------
976
977#[derive(Clone, Copy, Debug, Eq, PartialEq)]
978#[non_exhaustive]
979pub enum RelativeFromStrError {
980    /// The name could not be parsed.
981    FromStr(FromStrError),
982
983    /// The parsed name was ended in a dot.
984    AbsoluteName,
985}
986
987//--- From
988
989impl From<FromStrError> for RelativeFromStrError {
990    fn from(src: FromStrError) -> Self {
991        Self::FromStr(src)
992    }
993}
994
995//--- Display and Error
996
997impl fmt::Display for RelativeFromStrError {
998    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
999        match self {
1000            RelativeFromStrError::FromStr(err) => err.fmt(f),
1001            RelativeFromStrError::AbsoluteName => {
1002                f.write_str("absolute domain name")
1003            }
1004        }
1005    }
1006}
1007
1008#[cfg(feature = "std")]
1009impl std::error::Error for RelativeFromStrError {}
1010
1011//------------ StripSuffixError ----------------------------------------------
1012
1013/// An attempt was made to strip a suffix that wasn’t actually a suffix.
1014#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1015pub struct StripSuffixError;
1016
1017//--- Display and Error
1018
1019impl fmt::Display for StripSuffixError {
1020    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1021        f.write_str("suffix not found")
1022    }
1023}
1024
1025#[cfg(feature = "std")]
1026impl std::error::Error for StripSuffixError {}
1027
1028//============ Testing =======================================================
1029
1030#[cfg(test)]
1031mod test {
1032    use super::*;
1033
1034    #[cfg(feature = "std")]
1035    macro_rules! assert_panic {
1036        ( $cond:expr ) => {{
1037            let result = std::panic::catch_unwind(|| $cond);
1038            assert!(result.is_err());
1039        }};
1040    }
1041
1042    #[test]
1043    #[cfg(feature = "std")]
1044    fn impls() {
1045        fn assert_to_relative_dname<T: ToRelativeDname + ?Sized>(_: &T) {}
1046
1047        assert_to_relative_dname(
1048            RelativeDname::from_slice(b"\x03www".as_ref()).unwrap(),
1049        );
1050        assert_to_relative_dname(
1051            &RelativeDname::from_octets(b"\x03www").unwrap(),
1052        );
1053        assert_to_relative_dname(
1054            &RelativeDname::from_octets(b"\x03www".as_ref()).unwrap(),
1055        );
1056        assert_to_relative_dname(
1057            &RelativeDname::from_octets(Vec::from(b"\x03www".as_ref()))
1058                .unwrap(),
1059        );
1060    }
1061
1062    #[cfg(feature = "bytes")]
1063    #[test]
1064    fn impl_bytes() {
1065        fn assert_to_relative_dname<T: ToRelativeDname + ?Sized>(_: &T) {}
1066
1067        assert_to_relative_dname(
1068            &RelativeDname::from_octets(Bytes::from(b"\x03www".as_ref()))
1069                .unwrap(),
1070        );
1071    }
1072
1073    #[test]
1074    fn empty() {
1075        assert_eq!(RelativeDname::empty_slice().as_slice(), b"");
1076        assert_eq!(RelativeDname::empty_ref().as_slice(), b"");
1077
1078        #[cfg(feature = "std")]
1079        {
1080            assert_eq!(RelativeDname::empty_vec().as_slice(), b"");
1081        }
1082    }
1083
1084    #[test]
1085    fn wildcard() {
1086        assert_eq!(RelativeDname::wildcard_slice().as_slice(), b"\x01*");
1087        assert_eq!(RelativeDname::wildcard_ref().as_slice(), b"\x01*");
1088
1089        #[cfg(feature = "std")]
1090        {
1091            assert_eq!(RelativeDname::wildcard_vec().as_slice(), b"\x01*");
1092        }
1093    }
1094
1095    #[cfg(feature = "bytes")]
1096    #[test]
1097    fn literals_bytes() {
1098        assert_eq!(RelativeDname::empty_bytes().as_slice(), b"");
1099        assert_eq!(RelativeDname::wildcard_bytes().as_slice(), b"\x01*");
1100    }
1101
1102    #[test]
1103    #[cfg(feature = "std")]
1104    fn from_slice() {
1105        // good names
1106        assert_eq!(RelativeDname::from_slice(b"").unwrap().as_slice(), b"");
1107        assert_eq!(
1108            RelativeDname::from_slice(b"\x03www").unwrap().as_slice(),
1109            b"\x03www"
1110        );
1111        assert_eq!(
1112            RelativeDname::from_slice(b"\x03www\x07example")
1113                .unwrap()
1114                .as_slice(),
1115            b"\x03www\x07example"
1116        );
1117
1118        // absolute names
1119        assert_eq!(
1120            RelativeDname::from_slice(b"\x03www\x07example\x03com\0"),
1121            Err(RelativeDnameError::AbsoluteName)
1122        );
1123        assert_eq!(
1124            RelativeDname::from_slice(b"\0"),
1125            Err(RelativeDnameError::AbsoluteName)
1126        );
1127
1128        // bytes shorter than what label length says.
1129        assert_eq!(
1130            RelativeDname::from_slice(b"\x03www\x07exa"),
1131            Err(RelativeDnameError::ShortInput)
1132        );
1133
1134        // label 63 long ok, 64 bad.
1135        let mut slice = [0u8; 64];
1136        slice[0] = 63;
1137        assert!(RelativeDname::from_slice(&slice[..]).is_ok());
1138        let mut slice = [0u8; 65];
1139        slice[0] = 64;
1140        assert!(RelativeDname::from_slice(&slice[..]).is_err());
1141
1142        // name 254 long ok, 255 bad.
1143        let mut buf = Vec::new();
1144        for _ in 0..25 {
1145            buf.extend_from_slice(b"\x09123456789");
1146        }
1147        assert_eq!(buf.len(), 250);
1148        let mut tmp = buf.clone();
1149        tmp.extend_from_slice(b"\x03123");
1150        assert_eq!(RelativeDname::from_slice(&tmp).map(|_| ()), Ok(()));
1151        buf.extend_from_slice(b"\x041234");
1152        assert!(RelativeDname::from_slice(&buf).is_err());
1153
1154        // bad label heads: compressed, other types.
1155        assert_eq!(
1156            RelativeDname::from_slice(b"\xa2asdasds"),
1157            Err(LabelTypeError::Undefined.into())
1158        );
1159        assert_eq!(
1160            RelativeDname::from_slice(b"\x62asdasds"),
1161            Err(LabelTypeError::Extended(0x62).into())
1162        );
1163        assert_eq!(
1164            RelativeDname::from_slice(b"\xccasdasds"),
1165            Err(RelativeDnameError::CompressedName)
1166        );
1167    }
1168
1169    #[test]
1170    #[cfg(feature = "std")]
1171    fn from_str() {
1172        // empty name
1173        assert_eq!(RelativeDname::vec_from_str("").unwrap().as_slice(), b"");
1174
1175        // relative name
1176        assert_eq!(
1177            RelativeDname::vec_from_str("www.example")
1178                .unwrap()
1179                .as_slice(),
1180            b"\x03www\x07example"
1181        );
1182
1183        // absolute name
1184        assert!(RelativeDname::vec_from_str("www.example.com.").is_err());
1185    }
1186
1187    #[test]
1188    #[cfg(feature = "std")]
1189    fn into_absolute() {
1190        assert_eq!(
1191            RelativeDname::from_octets(Vec::from(
1192                b"\x03www\x07example\x03com".as_ref()
1193            ))
1194            .unwrap()
1195            .into_absolute()
1196            .unwrap()
1197            .as_slice(),
1198            b"\x03www\x07example\x03com\0"
1199        );
1200
1201        // Check that a 254 octets long relative name converts fine.
1202        let mut buf = Vec::new();
1203        for _ in 0..25 {
1204            buf.extend_from_slice(b"\x09123456789");
1205        }
1206        assert_eq!(buf.len(), 250);
1207        let mut tmp = buf.clone();
1208        tmp.extend_from_slice(b"\x03123");
1209        RelativeDname::from_octets(tmp)
1210            .unwrap()
1211            .into_absolute()
1212            .unwrap();
1213    }
1214
1215    #[test]
1216    #[cfg(feature = "std")]
1217    fn make_canonical() {
1218        let mut name = Dname::vec_from_str("wWw.exAmpLE.coM.").unwrap();
1219        name.make_canonical();
1220        assert_eq!(
1221            name,
1222            Dname::from_octets(b"\x03www\x07example\x03com\0").unwrap()
1223        );
1224    }
1225
1226    // chain is tested with the Chain type.
1227
1228    #[test]
1229    fn chain_root() {
1230        assert_eq!(
1231            Dname::from_octets(b"\x03www\x07example\x03com\0").unwrap(),
1232            RelativeDname::from_octets(b"\x03www\x07example\x03com")
1233                .unwrap()
1234                .chain_root()
1235        );
1236    }
1237
1238    #[test]
1239    fn iter() {
1240        use crate::base::name::dname::test::cmp_iter;
1241
1242        cmp_iter(RelativeDname::empty_ref().iter(), &[]);
1243        cmp_iter(RelativeDname::wildcard_ref().iter(), &[b"*"]);
1244        cmp_iter(
1245            RelativeDname::from_slice(b"\x03www\x07example\x03com")
1246                .unwrap()
1247                .iter(),
1248            &[b"www", b"example", b"com"],
1249        );
1250    }
1251
1252    #[test]
1253    fn iter_back() {
1254        use crate::base::name::dname::test::cmp_iter_back;
1255
1256        cmp_iter_back(RelativeDname::empty_ref().iter(), &[]);
1257        cmp_iter_back(RelativeDname::wildcard_ref().iter(), &[b"*"]);
1258        cmp_iter_back(
1259            RelativeDname::from_slice(b"\x03www\x07example\x03com")
1260                .unwrap()
1261                .iter(),
1262            &[b"com", b"example", b"www"],
1263        );
1264    }
1265
1266    #[test]
1267    fn label_count() {
1268        assert_eq!(RelativeDname::empty_ref().label_count(), 0);
1269        assert_eq!(RelativeDname::wildcard_slice().label_count(), 1);
1270        assert_eq!(
1271            RelativeDname::from_slice(b"\x03www\x07example\x03com")
1272                .unwrap()
1273                .label_count(),
1274            3
1275        );
1276    }
1277
1278    #[test]
1279    fn first() {
1280        assert_eq!(RelativeDname::empty_slice().first(), None);
1281        assert_eq!(
1282            RelativeDname::from_slice(b"\x03www")
1283                .unwrap()
1284                .first()
1285                .unwrap()
1286                .as_slice(),
1287            b"www"
1288        );
1289        assert_eq!(
1290            RelativeDname::from_slice(b"\x03www\x07example")
1291                .unwrap()
1292                .first()
1293                .unwrap()
1294                .as_slice(),
1295            b"www"
1296        );
1297    }
1298
1299    #[test]
1300    fn last() {
1301        assert_eq!(RelativeDname::empty_slice().last(), None);
1302        assert_eq!(
1303            RelativeDname::from_slice(b"\x03www")
1304                .unwrap()
1305                .last()
1306                .unwrap()
1307                .as_slice(),
1308            b"www"
1309        );
1310        assert_eq!(
1311            RelativeDname::from_slice(b"\x03www\x07example")
1312                .unwrap()
1313                .last()
1314                .unwrap()
1315                .as_slice(),
1316            b"example"
1317        );
1318    }
1319
1320    #[test]
1321    fn ndots() {
1322        assert_eq!(RelativeDname::empty_slice().ndots(), 0);
1323        assert_eq!(RelativeDname::from_slice(b"\x03www").unwrap().ndots(), 0);
1324        assert_eq!(
1325            RelativeDname::from_slice(b"\x03www\x07example")
1326                .unwrap()
1327                .ndots(),
1328            1
1329        );
1330    }
1331
1332    #[test]
1333    fn starts_with() {
1334        let matrix = [
1335            (
1336                RelativeDname::empty_slice(),
1337                [true, false, false, false, false, false],
1338            ),
1339            (
1340                RelativeDname::from_slice(b"\x03www").unwrap(),
1341                [true, true, false, false, false, false],
1342            ),
1343            (
1344                RelativeDname::from_slice(b"\x03www\x07example").unwrap(),
1345                [true, true, true, false, false, false],
1346            ),
1347            (
1348                RelativeDname::from_slice(b"\x03www\x07example\x03com")
1349                    .unwrap(),
1350                [true, true, true, true, false, false],
1351            ),
1352            (
1353                RelativeDname::from_slice(b"\x07example\x03com").unwrap(),
1354                [true, false, false, false, true, false],
1355            ),
1356            (
1357                RelativeDname::from_slice(b"\x03com").unwrap(),
1358                [true, false, false, false, false, true],
1359            ),
1360        ];
1361        for i in 0..6 {
1362            for j in 0..6 {
1363                assert_eq!(
1364                    matrix[i].0.starts_with(&matrix[j].0),
1365                    matrix[i].1[j],
1366                    "i={}, j={}",
1367                    i,
1368                    j
1369                )
1370            }
1371        }
1372    }
1373
1374    #[test]
1375    fn ends_with() {
1376        let matrix = [
1377            (
1378                RelativeDname::empty_slice(),
1379                [true, false, false, false, false, false],
1380            ),
1381            (
1382                RelativeDname::from_slice(b"\x03www").unwrap(),
1383                [true, true, false, false, false, false],
1384            ),
1385            (
1386                RelativeDname::from_slice(b"\x03www\x07example").unwrap(),
1387                [true, false, true, false, false, false],
1388            ),
1389            (
1390                RelativeDname::from_slice(b"\x03www\x07example\x03com")
1391                    .unwrap(),
1392                [true, false, false, true, true, true],
1393            ),
1394            (
1395                RelativeDname::from_slice(b"\x07example\x03com").unwrap(),
1396                [true, false, false, false, true, true],
1397            ),
1398            (
1399                RelativeDname::from_slice(b"\x03com").unwrap(),
1400                [true, false, false, false, false, true],
1401            ),
1402        ];
1403        for i in 0..matrix.len() {
1404            for j in 0..matrix.len() {
1405                assert_eq!(
1406                    matrix[i].0.ends_with(&matrix[j].0),
1407                    matrix[i].1[j],
1408                    "i={}, j={}",
1409                    i,
1410                    j
1411                )
1412            }
1413        }
1414    }
1415
1416    #[test]
1417    fn is_label_start() {
1418        let wec =
1419            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
1420
1421        assert!(wec.is_label_start(0)); // \x03
1422        assert!(!wec.is_label_start(1)); // w
1423        assert!(!wec.is_label_start(2)); // w
1424        assert!(!wec.is_label_start(3)); // w
1425        assert!(wec.is_label_start(4)); // \x07
1426        assert!(!wec.is_label_start(5)); // e
1427        assert!(!wec.is_label_start(6)); // x
1428        assert!(!wec.is_label_start(7)); // a
1429        assert!(!wec.is_label_start(8)); // m
1430        assert!(!wec.is_label_start(9)); // p
1431        assert!(!wec.is_label_start(10)); // l
1432        assert!(!wec.is_label_start(11)); // e
1433        assert!(wec.is_label_start(12)); // \x03
1434        assert!(!wec.is_label_start(13)); // c
1435        assert!(!wec.is_label_start(14)); // o
1436        assert!(!wec.is_label_start(15)); // m
1437        assert!(wec.is_label_start(16)); // empty label
1438        assert!(!wec.is_label_start(17)); //
1439    }
1440
1441    #[test]
1442    #[cfg(feature = "std")]
1443    fn slice() {
1444        let wec =
1445            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
1446        assert_eq!(wec.slice(0..4).as_slice(), b"\x03www");
1447        assert_eq!(wec.slice(0..12).as_slice(), b"\x03www\x07example");
1448        assert_eq!(wec.slice(4..12).as_slice(), b"\x07example");
1449        assert_eq!(wec.slice(4..16).as_slice(), b"\x07example\x03com");
1450
1451        assert_panic!(wec.slice(0..3));
1452        assert_panic!(wec.slice(1..4));
1453        assert_panic!(wec.slice(0..11));
1454        assert_panic!(wec.slice(1..12));
1455        assert_panic!(wec.slice(0..17));
1456        assert_panic!(wec.slice(4..17));
1457        assert_panic!(wec.slice(0..18));
1458    }
1459
1460    #[test]
1461    #[cfg(feature = "std")]
1462    fn range() {
1463        let wec =
1464            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1465                .unwrap();
1466        assert_eq!(wec.range(0..4).as_slice(), b"\x03www");
1467        assert_eq!(wec.range(0..12).as_slice(), b"\x03www\x07example");
1468        assert_eq!(wec.range(4..12).as_slice(), b"\x07example");
1469        assert_eq!(wec.range(4..16).as_slice(), b"\x07example\x03com");
1470
1471        assert_panic!(wec.range(0..3));
1472        assert_panic!(wec.range(1..4));
1473        assert_panic!(wec.range(0..11));
1474        assert_panic!(wec.range(1..12));
1475        assert_panic!(wec.range(0..17));
1476        assert_panic!(wec.range(4..17));
1477        assert_panic!(wec.range(0..18));
1478    }
1479
1480    #[test]
1481    #[cfg(feature = "std")]
1482    fn split() {
1483        let wec =
1484            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1485                .unwrap();
1486
1487        let (left, right) = wec.split(0);
1488        assert_eq!(left.as_slice(), b"");
1489        assert_eq!(right.as_slice(), b"\x03www\x07example\x03com");
1490
1491        let (left, right) = wec.split(4);
1492        assert_eq!(left.as_slice(), b"\x03www");
1493        assert_eq!(right.as_slice(), b"\x07example\x03com");
1494
1495        let (left, right) = wec.split(12);
1496        assert_eq!(left.as_slice(), b"\x03www\x07example");
1497        assert_eq!(right.as_slice(), b"\x03com");
1498
1499        let (left, right) = wec.split(16);
1500        assert_eq!(left.as_slice(), b"\x03www\x07example\x03com");
1501        assert_eq!(right.as_slice(), b"");
1502
1503        assert_panic!(wec.split(1));
1504        assert_panic!(wec.split(14));
1505        assert_panic!(wec.split(17));
1506        assert_panic!(wec.split(18));
1507    }
1508
1509    #[test]
1510    #[cfg(feature = "std")]
1511    fn truncate() {
1512        let wec =
1513            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1514                .unwrap();
1515
1516        let mut tmp = wec.clone();
1517        tmp.truncate(0);
1518        assert_eq!(tmp.as_slice(), b"");
1519
1520        let mut tmp = wec.clone();
1521        tmp.truncate(4);
1522        assert_eq!(tmp.as_slice(), b"\x03www");
1523
1524        let mut tmp = wec.clone();
1525        tmp.truncate(12);
1526        assert_eq!(tmp.as_slice(), b"\x03www\x07example");
1527
1528        let mut tmp = wec.clone();
1529        tmp.truncate(16);
1530        assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
1531
1532        assert_panic!(wec.clone().truncate(1));
1533        assert_panic!(wec.clone().truncate(14));
1534        assert_panic!(wec.clone().truncate(17));
1535        assert_panic!(wec.clone().truncate(18));
1536    }
1537
1538    #[test]
1539    fn split_first() {
1540        let wec =
1541            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1542                .unwrap();
1543
1544        let (label, wec) = wec.split_first().unwrap();
1545        assert_eq!(label.as_slice(), b"www");
1546        assert_eq!(wec.as_slice(), b"\x07example\x03com");
1547
1548        let (label, wec) = wec.split_first().unwrap();
1549        assert_eq!(label.as_slice(), b"example");
1550        assert_eq!(wec.as_slice(), b"\x03com");
1551
1552        let (label, wec) = wec.split_first().unwrap();
1553        assert_eq!(label.as_slice(), b"com");
1554        assert_eq!(wec.as_slice(), b"");
1555        assert!(wec.split_first().is_none());
1556    }
1557
1558    #[test]
1559    fn parent() {
1560        let wec =
1561            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1562                .unwrap();
1563
1564        let wec = wec.parent().unwrap();
1565        assert_eq!(wec.as_slice(), b"\x07example\x03com");
1566
1567        let wec = wec.parent().unwrap();
1568        assert_eq!(wec.as_slice(), b"\x03com");
1569
1570        let wec = wec.parent().unwrap();
1571        assert_eq!(wec.as_slice(), b"");
1572
1573        assert!(wec.parent().is_none());
1574    }
1575
1576    #[test]
1577    fn strip_suffix() {
1578        let wec =
1579            RelativeDname::from_octets(b"\x03www\x07example\x03com".as_ref())
1580                .unwrap();
1581        let ec = RelativeDname::from_octets(b"\x07example\x03com".as_ref())
1582            .unwrap();
1583        let c = RelativeDname::from_octets(b"\x03com".as_ref()).unwrap();
1584        let wen =
1585            RelativeDname::from_octets(b"\x03www\x07example\x03net".as_ref())
1586                .unwrap();
1587        let en = RelativeDname::from_octets(b"\x07example\x03net".as_ref())
1588            .unwrap();
1589        let n = RelativeDname::from_slice(b"\x03net".as_ref()).unwrap();
1590
1591        let mut tmp = wec.clone();
1592        assert_eq!(tmp.strip_suffix(&wec), Ok(()));
1593        assert_eq!(tmp.as_slice(), b"");
1594
1595        let mut tmp = wec.clone();
1596        assert_eq!(tmp.strip_suffix(&ec), Ok(()));
1597        assert_eq!(tmp.as_slice(), b"\x03www");
1598
1599        let mut tmp = wec.clone();
1600        assert_eq!(tmp.strip_suffix(&c), Ok(()));
1601        assert_eq!(tmp.as_slice(), b"\x03www\x07example");
1602
1603        let mut tmp = wec.clone();
1604        assert_eq!(tmp.strip_suffix(&RelativeDname::empty_ref()), Ok(()));
1605        assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
1606
1607        assert_eq!(wec.clone().strip_suffix(&wen), Err(StripSuffixError));
1608        assert_eq!(wec.clone().strip_suffix(&en), Err(StripSuffixError));
1609        assert_eq!(wec.clone().strip_suffix(&n), Err(StripSuffixError));
1610    }
1611
1612    // No test for Compose since the implementation is so simple.
1613
1614    #[test]
1615    fn eq() {
1616        assert_eq!(
1617            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1618            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap()
1619        );
1620        assert_eq!(
1621            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1622            RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com").unwrap()
1623        );
1624        assert_eq!(
1625            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1626            &RelativeDname::from_octets(b"\x03www")
1627                .unwrap()
1628                .chain(
1629                    RelativeDname::from_octets(b"\x07example\x03com")
1630                        .unwrap()
1631                )
1632                .unwrap()
1633        );
1634        assert_eq!(
1635            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1636            &RelativeDname::from_octets(b"\x03wWw")
1637                .unwrap()
1638                .chain(
1639                    RelativeDname::from_octets(b"\x07eXAMple\x03coM")
1640                        .unwrap()
1641                )
1642                .unwrap()
1643        );
1644
1645        assert_ne!(
1646            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1647            RelativeDname::from_slice(b"\x03ww4\x07example\x03com").unwrap()
1648        );
1649        assert_ne!(
1650            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
1651            &RelativeDname::from_octets(b"\x03www")
1652                .unwrap()
1653                .chain(
1654                    RelativeDname::from_octets(b"\x073xample\x03com")
1655                        .unwrap()
1656                )
1657                .unwrap()
1658        );
1659    }
1660
1661    #[test]
1662    fn cmp() {
1663        use core::cmp::Ordering;
1664
1665        // The following is taken from section 6.1 of RFC 4034.
1666        let names = [
1667            RelativeDname::from_slice(b"\x07example").unwrap(),
1668            RelativeDname::from_slice(b"\x01a\x07example").unwrap(),
1669            RelativeDname::from_slice(b"\x08yljkjljk\x01a\x07example")
1670                .unwrap(),
1671            RelativeDname::from_slice(b"\x01Z\x01a\x07example").unwrap(),
1672            RelativeDname::from_slice(b"\x04zABC\x01a\x07example").unwrap(),
1673            RelativeDname::from_slice(b"\x01z\x07example").unwrap(),
1674            RelativeDname::from_slice(b"\x01\x01\x01z\x07example").unwrap(),
1675            RelativeDname::from_slice(b"\x01*\x01z\x07example").unwrap(),
1676            RelativeDname::from_slice(b"\x01\xc8\x01z\x07example").unwrap(),
1677        ];
1678        for i in 0..names.len() {
1679            for j in 0..names.len() {
1680                let ord = i.cmp(&j);
1681                assert_eq!(names[i].partial_cmp(names[j]), Some(ord));
1682                assert_eq!(names[i].cmp(names[j]), ord);
1683            }
1684        }
1685
1686        let n1 =
1687            RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
1688        let n2 =
1689            RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com").unwrap();
1690        assert_eq!(n1.partial_cmp(n2), Some(Ordering::Equal));
1691        assert_eq!(n1.cmp(n2), Ordering::Equal);
1692    }
1693
1694    #[test]
1695    #[cfg(feature = "std")]
1696    fn hash() {
1697        use std::collections::hash_map::DefaultHasher;
1698        use std::hash::{Hash, Hasher};
1699
1700        let mut s1 = DefaultHasher::new();
1701        let mut s2 = DefaultHasher::new();
1702        RelativeDname::from_slice(b"\x03www\x07example\x03com")
1703            .unwrap()
1704            .hash(&mut s1);
1705        RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com")
1706            .unwrap()
1707            .hash(&mut s2);
1708        assert_eq!(s1.finish(), s2.finish());
1709    }
1710
1711    // Display and Debug skipped for now.
1712
1713    #[cfg(all(feature = "serde", feature = "std"))]
1714    #[test]
1715    fn ser_de() {
1716        use serde_test::{assert_tokens, Configure, Token};
1717
1718        let name = RelativeDname::from_octets(Vec::from(
1719            b"\x03www\x07example\x03com".as_ref(),
1720        ))
1721        .unwrap();
1722        assert_tokens(
1723            &name.clone().compact(),
1724            &[
1725                Token::NewtypeStruct {
1726                    name: "RelativeDname",
1727                },
1728                Token::ByteBuf(b"\x03www\x07example\x03com"),
1729            ],
1730        );
1731        assert_tokens(
1732            &name.readable(),
1733            &[
1734                Token::NewtypeStruct {
1735                    name: "RelativeDname",
1736                },
1737                Token::Str("www.example.com"),
1738            ],
1739        );
1740    }
1741}