domain_core/bits/name/
label.rs1use std::{cmp, fmt, hash, ops};
7use bytes::BufMut;
8use ::bits::compose::Compose;
9use ::bits::parse::ShortBuf;
10
11
12pub struct Label([u8]);
39
40impl Label {
43 pub(super) unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
45 &*(slice as *const [u8] as *const Self)
46 }
47
48 pub fn root() -> &'static Self {
52 unsafe { Self::from_slice_unchecked(b"") }
53 }
54
55 pub fn wildcard() -> &'static Self {
57 unsafe { Self::from_slice_unchecked(b"*") }
58 }
59
60 pub fn from_slice(slice: &[u8]) -> Result<&Self, LongLabelError> {
64 if slice.len() > 63 {
65 Err(LongLabelError)
66 }
67 else {
68 Ok(unsafe { Self::from_slice_unchecked(slice) })
69 }
70 }
71
72 pub fn split_from(slice: &[u8])
77 -> Result<(&Self, &[u8]), SplitLabelError> {
78 let head = match slice.get(0) {
79 Some(ch) => *ch,
80 None => return Err(SplitLabelError::ShortBuf)
81 };
82 let end = match head {
83 0 ... 0x3F => (head as usize) + 1,
84 0x40 ... 0x7F => {
85 return Err(
86 SplitLabelError::BadType(LabelTypeError::Extended(head))
87 )
88 }
89 0xC0 ... 0xFF => {
90 let res = match slice.get(1) {
91 Some(ch) => u16::from(*ch),
92 None => return Err(SplitLabelError::ShortBuf)
93 };
94 let res = res | ((u16::from(head) & 0x3F) << 8);
95 return Err(SplitLabelError::Pointer(res))
96 }
97 _ => {
98 return Err(
99 SplitLabelError::BadType(LabelTypeError::Undefined)
100 )
101 }
102 };
103 if slice.len() < end {
104 return Err(SplitLabelError::ShortBuf)
105 }
106 Ok((unsafe { Self::from_slice_unchecked(&slice[1..end]) },
107 &slice[end..]))
108 }
109
110 pub fn as_slice(&self) -> &[u8] {
112 self.as_ref()
113 }
114
115 pub fn as_slice_mut(&mut self) -> &mut [u8] {
117 self.as_mut()
118 }
119}
120
121impl Label {
124 pub fn is_root(&self) -> bool {
126 self.is_empty()
127 }
128}
129
130
131impl Compose for Label {
134 fn compose_len(&self) -> usize {
135 self.len() + 1
136 }
137
138 fn compose<B: BufMut>(&self, buf: &mut B) {
139 buf.put_u8(self.len() as u8);
140 buf.put_slice(self.as_ref());
141 }
142}
143
144
145impl ops::Deref for Label {
148 type Target = [u8];
149
150 fn deref(&self) -> &[u8] {
151 self.as_ref()
152 }
153}
154
155impl ops::DerefMut for Label {
156 fn deref_mut(&mut self) -> &mut [u8] {
157 self.as_mut()
158 }
159}
160
161impl AsRef<[u8]> for Label {
162 fn as_ref(&self) -> &[u8] {
163 unsafe { &*(self as *const Self as *const [u8]) }
164 }
165}
166
167impl AsMut<[u8]> for Label {
168 fn as_mut(&mut self) -> &mut [u8] {
169 unsafe { &mut *(self as *mut Label as *mut [u8]) }
170 }
171}
172
173
174impl PartialEq for Label {
177 fn eq(&self, other: &Self) -> bool {
178 self.eq_ignore_ascii_case(other)
179 }
180}
181
182impl Eq for Label { }
183
184
185impl PartialOrd for Label {
188 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
198 self.iter().map(u8::to_ascii_lowercase).partial_cmp(
199 other.iter().map(u8::to_ascii_lowercase)
200 )
201 }
202}
203
204impl Ord for Label {
205 fn cmp(&self, other: &Self) -> cmp::Ordering {
206 self.iter().map(u8::to_ascii_lowercase).cmp(
207 other.iter().map(u8::to_ascii_lowercase)
208 )
209 }
210}
211
212
213impl hash::Hash for Label {
216 fn hash<H: hash::Hasher>(&self, state: &mut H) {
217 (self.len() as u8).hash(state);
220 for c in self.iter() {
221 c.to_ascii_lowercase().hash(state)
222 }
223 }
224}
225
226
227impl<'a> IntoIterator for &'a Label {
230 type Item = &'a u8;
231 type IntoIter = ::std::slice::Iter<'a, u8>;
232
233 fn into_iter(self) -> Self::IntoIter {
234 self.iter()
235 }
236}
237
238
239impl fmt::Display for Label {
242 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243 for &ch in self.iter() {
244 if ch == b' ' || ch == b'.' || ch == b'\\' {
245 write!(f, "\\{}", ch as char)?;
246 }
247 else if ch < b' ' || ch >= 0x7F {
248 write!(f, "\\{:03}", ch)?;
249 }
250 else {
251 write!(f, "{}", (ch as char))?;
252 }
253 }
254 Ok(())
255 }
256}
257
258impl fmt::Debug for Label {
259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
260 f.write_str("Label(")?;
261 fmt::Display::fmt(self, f)?;
262 f.write_str(")")
263 }
264}
265
266
267#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
271pub enum LabelTypeError {
272 #[fail(display="undefined label type")]
274 Undefined,
275
276 #[fail(display="unknown extended label 0x{:02x}", _0)]
281 Extended(u8),
282}
283
284
285#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
289#[fail(display="long label")]
290pub struct LongLabelError;
291
292
293#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
297pub enum SplitLabelError {
298 #[fail(display="compressed domain name")]
300 Pointer(u16),
301
302 #[fail(display="{}", _0)]
304 BadType(LabelTypeError),
305
306 #[fail(display="unexpected end of input")]
308 ShortBuf,
309}
310
311impl From<LabelTypeError> for SplitLabelError {
312 fn from(err: LabelTypeError) -> SplitLabelError {
313 SplitLabelError::BadType(err)
314 }
315}
316
317impl From<ShortBuf> for SplitLabelError {
318 fn from(_: ShortBuf) -> SplitLabelError {
319 SplitLabelError::ShortBuf
320 }
321}
322
323
324#[cfg(test)]
327mod test {
328 use super::*;
329
330 #[test]
331 fn from_slice() {
332 let x = [0u8; 10];
333 assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(),
334 &x[..]);
335 let x = [0u8; 63];
336 assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(),
337 &x[..]);
338 let x = [0u8; 64];
339 assert!(Label::from_slice(&x[..]).is_err());
340 }
341
342 #[test]
343 fn split_from() {
344 assert_eq!(Label::split_from(b"\x03www\x07example\x03com\0").unwrap(),
346 (Label::from_slice(b"www").unwrap(),
347 &b"\x07example\x03com\0"[..]));
348
349 assert_eq!(Label::split_from(b"\x03www").unwrap(),
351 (Label::from_slice(b"www").unwrap(),
352 &b""[..]));
353
354 assert_eq!(Label::split_from(b"\0some").unwrap(),
356 (Label::from_slice(b"").unwrap(),
357 &b"some"[..]));
358
359 assert_eq!(Label::split_from(b"\x03ww"),
361 Err(SplitLabelError::ShortBuf));
362
363 assert_eq!(Label::split_from(b""),
365 Err(SplitLabelError::ShortBuf));
366
367 assert_eq!(Label::split_from(b"\xc0\x05foo"),
369 Err(SplitLabelError::Pointer(5)));
370
371 assert_eq!(Label::split_from(b"\xb3foo"),
373 Err(LabelTypeError::Undefined.into()));
374
375 assert_eq!(Label::split_from(b"\x66foo"),
377 Err(LabelTypeError::Extended(0x66).into()));
378 }
379
380 #[test]
381 fn compose() {
382 use bytes::BytesMut;
383
384 let mut buf = BytesMut::with_capacity(64);
385 assert_eq!(Label::root().compose_len(), 1);
386 Label::root().compose(&mut buf);
387 assert_eq!(buf.freeze(), &b"\0"[..]);
388
389 let mut buf = BytesMut::with_capacity(64);
390 let label = Label::from_slice(b"123").unwrap();
391 assert_eq!(label.compose_len(), 4);
392 label.compose(&mut buf);
393 assert_eq!(buf.freeze(), &b"\x03123"[..]);
394 }
395
396 #[test]
397 fn eq() {
398 assert_eq!(Label::from_slice(b"example").unwrap(),
399 Label::from_slice(b"eXAMple").unwrap());
400 assert_ne!(Label::from_slice(b"example").unwrap(),
401 Label::from_slice(b"e4ample").unwrap());
402 }
403
404 #[test]
405 fn cmp() {
406 use std::cmp::Ordering;
407
408 let labels = [Label::root(),
409 Label::from_slice(b"\x01").unwrap(),
410 Label::from_slice(b"*").unwrap(),
411 Label::from_slice(b"\xc8").unwrap()];
412 for i in 0..labels.len() {
413 for j in 0..labels.len() {
414 let ord = if i < j { Ordering::Less }
415 else if i == j { Ordering::Equal }
416 else { Ordering::Greater };
417 assert_eq!(labels[i].partial_cmp(&labels[j]), Some(ord));
418 assert_eq!(labels[i].cmp(&labels[j]), ord);
419 }
420 }
421
422 let l1 = Label::from_slice(b"example").unwrap();
423 let l2 = Label::from_slice(b"eXAMple").unwrap();
424 assert_eq!(l1.partial_cmp(&l2), Some(Ordering::Equal));
425 assert_eq!(l1.cmp(&l2), Ordering::Equal);
426 }
427
428 #[test]
429 fn hash() {
430 use std::collections::hash_map::DefaultHasher;
431 use std::hash::{Hash, Hasher};
432
433 let mut s1 = DefaultHasher::new();
434 let mut s2 = DefaultHasher::new();
435 Label::from_slice(b"example").unwrap().hash(&mut s1);
436 Label::from_slice(b"eXAMple").unwrap().hash(&mut s2);
437 assert_eq!(s1.finish(), s2.finish());
438 }
439}