domain_core/bits/name/
traits.rs

1//! Domain name-related traits.
2//!
3/// This is a private module. Its public traits are re-exported by the parent.
4
5use std::cmp;
6use bytes::BytesMut;
7use ::bits::compose::{Compose, Compress};
8use super::chain::{Chain, LongChainError};
9use super::dname::Dname;
10use super::label::Label;
11use super::relative::RelativeDname;
12
13
14//------------ ToLabelIter ---------------------------------------------------
15
16/// A type that can produce an iterator over its labels.
17///
18/// This trait is used as a trait bound for both [`ToDname`] and
19/// [`ToRelativeDname`]. It is separate since it has to be generic over the
20/// lifetime of the label reference but we don’t want to have this lifetime
21/// parameter pollute those traits.
22///
23/// [`ToDname`]: trait.ToDname.html
24/// [`ToRelativeDname`]: trait ToRelativeDname.html
25pub trait ToLabelIter<'a> {
26    /// The type of the iterator over the labels.
27    ///
28    /// This iterator types needs to be double ended so that we can deal with
29    /// name suffixes.
30    type LabelIter: Iterator<Item=&'a Label> + DoubleEndedIterator;
31
32    /// Returns an iterator over the labels.
33    fn iter_labels(&'a self) -> Self::LabelIter;
34
35    /// Determines whether `base` is a prefix of `self`.
36    fn starts_with<N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
37        let mut self_iter = self.iter_labels();
38        let mut base_iter = base.iter_labels();
39        loop {
40            match (self_iter.next(), base_iter.next()) {
41                (Some(sl), Some(bl)) => {
42                    if sl != bl { return false }
43                }
44                (_, None) => return true,
45                (None, Some(_)) => return false,
46            }
47        }
48    }
49
50    /// Determines whether `base` is a suffix of `self`.
51    fn ends_with<N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
52        let mut self_iter = self.iter_labels();
53        let mut base_iter = base.iter_labels();
54        loop {
55            match (self_iter.next_back(), base_iter.next_back()) {
56                (Some(sl), Some(bl)) => {
57                    if sl != bl { return false }
58                }
59                (_, None) => return true,
60                (None, Some(_)) =>  return false
61            }
62        }
63    }
64}
65
66impl<'a, 'b, N: ToLabelIter<'b>> ToLabelIter<'b> for &'a N {
67    type LabelIter = N::LabelIter;
68
69    fn iter_labels(&'b self) -> Self::LabelIter {
70        (*self).iter_labels()
71    }
72}
73
74
75//------------ ToDname -------------------------------------------------------
76
77/// A type that represents an absolute domain name.
78///
79/// An absolute domain name is a sequence of labels where the last label is
80/// the root label and where the wire-format representation is not longer than
81/// 255 characters. Implementers of this trait need to provide access to the
82/// label sequence via an iterator and know how to compose the wire-format
83/// representation into a buffer.
84///
85/// The most common types implementing this trait are [`Dname`],
86/// [`ParsedDname`], and [`Chain<L, R>`] where `R` is `ToDname` itself.
87///
88/// [`Chain<L, R>`]: struct.Chain.html
89/// [`Dname`]: struct.Dname.html
90/// [`ParsedDname`]: struct.ParsedDname.html
91pub trait ToDname: Compose + Compress + for<'a> ToLabelIter<'a> {
92    /// Creates an uncompressed value of the domain name.
93    ///
94    /// The method has a default implementation that composes the name into
95    /// a new buffer and returns this buffer. If the implementing type can
96    /// create a `Dname` more efficiently, then it should provide its
97    /// own implementation.
98    fn to_name(&self) -> Dname {
99        let mut bytes = BytesMut::with_capacity(self.compose_len());
100        self.compose(&mut bytes);
101        unsafe {
102            Dname::from_bytes_unchecked(bytes.freeze())
103        }
104    }
105
106    /// Returns a byte slice of the content if possible.
107    ///
108    /// If a value stores the domain name as one single byte sequence, it
109    /// should return a reference to this sequence here. If the name is
110    /// composed from multiple such sequences, it should return `None`.
111    ///
112    /// This method is used to optimize comparision operations between
113    /// two values that are indeed flat names.
114    fn as_flat_slice(&self) -> Option<&[u8]> {
115        None
116    }
117
118    /// Tests whether `self` and `other` are equal.
119    ///
120    /// This method can be used to implement `PartialEq` on types implementing
121    /// `ToDname` since a blanket implementation for all pairs of `ToDname`
122    /// is currently impossible.
123    ///
124    /// Domain names are compared ignoring ASCII case.
125    fn name_eq<N: ToDname>(&self, other: &N) -> bool {
126        if let (Some(left), Some(right)) = (self.as_flat_slice(),
127                                            other.as_flat_slice()) {
128            left.eq_ignore_ascii_case(right)
129        }
130        else {
131            self.iter_labels().eq(other.iter_labels())
132        }
133    }
134
135    /// Returns the ordering between `self` and `other`.
136    ///
137    /// This method can be used to implement both `PartialOrd` and `Ord` on
138    /// types implementing `ToDname` since a blanket implementation for all
139    /// pairs of `ToDname`s is currently not possible.
140    ///
141    /// Domain name order is determined according to the ‘canonical DNS
142    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
143    ///
144    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
145    fn name_cmp<N: ToDname>(&self, other: &N) -> cmp::Ordering {
146        let mut self_iter = self.iter_labels();
147        let mut other_iter = other.iter_labels();
148        loop {
149            match (self_iter.next_back(), other_iter.next_back()) {
150                (Some(left), Some(right)) => {
151                    match left.cmp(right) {
152                        cmp::Ordering::Equal => {}
153                        res => return res
154                    }
155                }
156                (None, Some(_)) => return cmp::Ordering::Less,
157                (Some(_), None) => return cmp::Ordering::Greater,
158                (None, None) => return cmp::Ordering::Equal
159            }
160        }
161    }
162}
163
164impl<'a, N: ToDname + 'a> ToDname for &'a N { }
165
166
167//------------ ToRelativeDname -----------------------------------------------
168
169/// A type that represents a relative domain name.
170///
171/// In order to be a relative domain name, a type needs to be able to
172/// provide a sequence of labels via an iterator where the last label is not
173/// the root label. The type also needs to be able to compose the wire-format
174/// representation of the domain name it represents which must not be longer
175/// than 254 characters. This limit has been chosen so that by attaching the
176/// one character long root label, a valid absolute name can be constructed
177/// from the relative name.
178///
179/// The most important types implementing this trait are [`RelativeDname`]
180/// and [`Chain<L,R>`] where `R` is a `ToRelativeDname` itself.
181///
182/// [`Chain<L, R>`]: struct.Chain.html
183/// [`RelativeDname`]: struct.RelativeDname.html
184pub trait ToRelativeDname: Compose + for<'a> ToLabelIter<'a> {
185    /// Creates an uncompressed value of the domain name.
186    ///
187    /// The method has a default implementation that composes the name into
188    /// a new buffer and returns this buffer. If the implementing type can
189    /// create a `RelativeDname` more efficiently, then it should provide its
190    /// own implementation.
191    fn to_name(&self) -> RelativeDname {
192        let mut bytes = BytesMut::with_capacity(self.compose_len());
193        self.compose(&mut bytes);
194        unsafe {
195            RelativeDname::from_bytes_unchecked(bytes.freeze())
196        }
197    }
198
199    /// Returns a byte slice of the content if possible.
200    ///
201    /// This method can is used to optimize comparision operations between
202    /// two values that are indeed flat names.
203    fn as_flat_slice(&self) -> Option<&[u8]> {
204        None
205    }
206
207    /// Returns a chain of this name and the provided absolute name.
208    fn chain<N: Compose>(
209        self,
210        suffix: N
211    ) -> Result<Chain<Self, N>, LongChainError>
212    where Self: Sized {
213        Chain::new(self, suffix)
214    }
215
216    /// Returns the absolute name by chaining it with the root label.
217    fn chain_root(self) -> Chain<Self, Dname>
218    where Self: Sized {
219        // Appending the root label will always work.
220        Chain::new(self, Dname::root()).unwrap()
221    }
222
223    /// Tests whether `self` and `other` are equal.
224    ///
225    /// This method can be used to implement `PartialEq` on types implementing
226    /// `ToDname` since a blanket implementation for all pairs of `ToDname`
227    /// is currently impossible.
228    ///
229    /// Domain names are compared ignoring ASCII case.
230    fn name_eq<N: ToRelativeDname>(&self, other: &N) -> bool {
231        if let (Some(left), Some(right)) = (self.as_flat_slice(),
232                                            other.as_flat_slice()) {
233            left.eq_ignore_ascii_case(right)
234        }
235        else {
236            self.iter_labels().eq(other.iter_labels())
237        }
238    }
239
240    /// Returns the ordering between `self` and `other`.
241    ///
242    /// This method can be used to implement both `PartialOrd` and `Ord` on
243    /// types implementing `ToDname` since a blanket implementation for all
244    /// pairs of `ToDname`s is currently not possible.
245    ///
246    /// Domain name order is determined according to the ‘canonical DNS
247    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
248    /// This section describes how absolute domain names are ordered only.
249    /// We will order relative domain names according to these rules as if
250    /// they had the same origin, i.e., as if they were relative to the
251    /// same name.
252    ///
253    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
254    fn name_cmp<N: ToRelativeDname>(&self, other: &N) -> cmp::Ordering {
255        let mut self_iter = self.iter_labels();
256        let mut other_iter = other.iter_labels();
257        loop {
258            match (self_iter.next_back(), other_iter.next_back()) {
259                (Some(left), Some(right)) => {
260                    match left.cmp(right) {
261                        cmp::Ordering::Equal => {}
262                        res => return res
263                    }
264                }
265                (None, Some(_)) => return cmp::Ordering::Less,
266                (Some(_), None) => return cmp::Ordering::Greater,
267                (None, None) => return cmp::Ordering::Equal
268            }
269        }
270    }
271}
272
273impl<'a, N: ToRelativeDname + 'a> ToRelativeDname for &'a N { }
274