domain/base/cmp.rs
1//! Additional traits for comparisions.
2//!
3//! These traits exist because there are several ways of compare domain
4//! names included in composite structures. Normally, names are compared
5//! ignoring ASCII case. This is what [`PartialEq`] and [`PartialOrd`] do for
6//! domain names. Consequently, when comparing resource records and record
7//! data that contain domain names, ASCII case should also be ignored.
8//!
9//! However, the canonical form of most resource type’s record data (apart
10//! from a small set of well-known types) requires names to be considered
11//! as they are for comparisons. In order to make it clear when this mode
12//! of comparision is used, this module defines a new trait [`CanonicalOrd`]
13//! that allows types to define how they should be compared in the context of
14//! DNSSEC. The trait is accompanied by `compose_canonical` methods on all
15//! types that have or may have a canonical form.
16
17use core::cmp::Ordering;
18
19/// A trait for the canonical sort order of values.
20///
21/// The canonical sort order is used in DNSSEC when multiple values are
22/// part of constructing or validating a signature. This sort order differs
23/// in some cases from the normal sort order. To avoid confusion, only this
24/// trait should be used when DNSSEC signatures are involved.
25///
26/// Canonical order is defined in [RFC 4034] and clarified in [RFC 6840]. It
27/// is defined for domain names and resource records within an RR set (i.e.,
28/// a set of records with the same owner name, class, and type).
29///
30/// For domain names, canonical order is the same as the ‘normal’ order as
31/// implemented through the [`PartialOrd`] and [`Ord`] traits: labels are
32/// compared from right to left (i.e, starting from the root label) with each
33/// pair of labels compared as octet sequences with ASCII letters lowercased
34/// before comparison. The [`ToName::name_cmp`] and
35/// [`ToRelativeName::name_cmp`] methods of the can be used to implement this
36/// canonical order for name types.
37///
38/// Resource records within an RR set are ordered by comparing the canonical
39/// wire-format representation of their record data as octet sequences. The
40/// canonical form differs from the regular form by lower-casing domain names
41/// included in the record data for the record types NS, MD, MF, CNAME, SOA,
42/// MB, MG, MR, PTR, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, SRV,
43/// DNAME, A6, and RRSIG. (NSEC is listed in [RFC 4034] but has been withdrawn
44/// by [RFC 6840]). This canonical representation is provided via their
45/// respective `compose_canonical` methods.
46///
47/// In order to help implementing this trait for record data types, there are
48/// implementations of it for some types that can appear in record data that
49/// sort differently in their composed representation than normally.
50///
51/// Apart from these explicit use cases, the [`CanonicalOrd`] trait is also
52/// implemented for the [`Record`] type to allow ordering records of a zone into
53/// RRsets. It does so by ordering by class first, then canonical owner,
54/// record type, and finally canonical record data. The reason for this
55/// somewhat odd ordering is that in this way not only are all records
56/// for the same owner name and class kept together, but also all the records
57/// subordinate to a owner name and class pair (i.e., the records for a zone)
58/// will sort together.
59///
60/// [`ToName::name_cmp`]: crate::base::name::ToName::name_cmp
61/// [`ToRelativeName::name_cmp`]: crate::base::name::ToRelativeName::name_cmp
62/// [`Record`]: crate::base::record::Record
63/// [RFC 4034]: https://tools.ietf.org/html/rfc4034
64/// [RFC 6840]: https://tools.ietf.org/html/rfc6840
65pub trait CanonicalOrd<Rhs: ?Sized = Self> {
66 /// Returns the canonical ordering between `self` and `other`.
67 #[must_use]
68 fn canonical_cmp(&self, other: &Rhs) -> Ordering;
69
70 /// Returns whether `self` is canonically less than `other`.
71 #[inline]
72 #[must_use]
73 fn canonical_lt(&self, other: &Rhs) -> bool {
74 matches!(self.canonical_cmp(other), Ordering::Less)
75 }
76
77 /// Returns whether `self` is canonically less than or equal to `other`.
78 #[inline]
79 #[must_use]
80 fn canonical_le(&self, other: &Rhs) -> bool {
81 matches!(self.canonical_cmp(other), Ordering::Less | Ordering::Equal)
82 }
83
84 /// Returns whether `self` is canonically greater than `other`.
85 #[inline]
86 #[must_use]
87 fn canonical_gt(&self, other: &Rhs) -> bool {
88 matches!(self.canonical_cmp(other), Ordering::Greater)
89 }
90
91 /// Returns whether `self` is canonically greater than or equal to `other`.
92 #[inline]
93 #[must_use]
94 fn canonical_ge(&self, other: &Rhs) -> bool {
95 matches!(
96 self.canonical_cmp(other),
97 Ordering::Greater | Ordering::Equal
98 )
99 }
100}