use std::{cmp, fmt, hash, ops};
use bytes::{BufMut, Bytes};
use ::bits::compose::Compose;
use super::builder::DnameBuilder;
use super::chain::{Chain, LongChainError};
use super::dname::Dname;
use super::label::{Label, LabelTypeError, SplitLabelError};
use super::traits::{ToLabelIter, ToRelativeDname};
#[derive(Clone)]
pub struct RelativeDname {
bytes: Bytes,
}
impl RelativeDname {
pub(super) unsafe fn from_bytes_unchecked(bytes: Bytes) -> Self {
RelativeDname { bytes }
}
pub fn empty() -> Self {
unsafe {
RelativeDname::from_bytes_unchecked(Bytes::from_static(b""))
}
}
pub fn wildcard() -> Self {
unsafe {
RelativeDname::from_bytes_unchecked(Bytes::from_static(b"\x01*"))
}
}
pub fn from_bytes(bytes: Bytes) -> Result<Self, RelativeDnameError> {
if bytes.len() > 254 {
return Err(RelativeDnameError::LongName)
}
{
let mut tmp = bytes.as_ref();
while !tmp.is_empty() {
let (label, tail) = Label::split_from(tmp)?;
if label.is_root() {
return Err(RelativeDnameError::AbsoluteName);
}
tmp = tail;
}
}
Ok(unsafe { RelativeDname::from_bytes_unchecked(bytes) })
}
pub fn from_slice(slice: &[u8]) -> Result<Self, RelativeDnameError> {
Self::from_bytes(slice.into())
}
pub fn as_bytes(&self) -> &Bytes {
&self.bytes
}
pub fn as_slice(&self) -> &[u8] {
self.bytes.as_ref()
}
pub fn into_bytes(self) -> Bytes {
self.bytes
}
pub fn into_builder(self) -> DnameBuilder {
let bytes = match self.bytes.try_mut() {
Ok(bytes) => bytes,
Err(bytes) => bytes.as_ref().into()
};
unsafe { DnameBuilder::from_bytes(bytes) }
}
pub fn into_absolute(self) -> Dname {
self.into_builder().into_dname().unwrap()
}
pub fn chain<N: Compose>(self, other: N)
-> Result<Chain<Self, N>, LongChainError> {
Chain::new(self, other)
}
pub fn chain_root(self) -> Chain<Self, Dname> {
self.chain(Dname::root()).unwrap()
}
}
impl RelativeDname {
pub fn iter(&self) -> DnameIter {
DnameIter::new(self.bytes.as_ref())
}
pub fn label_count(&self) -> usize {
self.iter().count()
}
pub fn first(&self) -> Option<&Label> {
self.iter().next()
}
pub fn last(&self) -> Option<&Label> {
self.iter().next_back()
}
pub fn ndots(&self) -> usize {
if self.is_empty() { 0 }
else {
self.label_count() - 1
}
}
pub fn starts_with<'a, N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
<Self as ToLabelIter>::starts_with(self, base)
}
pub fn ends_with<'a, N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
<Self as ToLabelIter>::ends_with(self, base)
}
pub fn is_label_start(&self, mut index: usize) -> bool {
if index == 0 {
return true
}
let mut tmp = self.as_slice();
while !tmp.is_empty() {
let (label, tail) = Label::split_from(tmp).unwrap();
let len = label.len() + 1;
if index < len {
return false
}
else if index == len {
return true
}
index -= len;
tmp = tail;
}
false
}
fn check_index(&self, index: usize) {
if !self.is_label_start(index) {
panic!("index not at start of a label");
}
}
pub fn slice(&self, begin: usize, end: usize) -> Self {
self.check_index(begin);
self.check_index(end);
unsafe { Self::from_bytes_unchecked(self.bytes.slice(begin, end)) }
}
pub fn slice_from(&self, begin: usize) -> Self {
self.check_index(begin);
unsafe { Self::from_bytes_unchecked(self.bytes.slice_from(begin)) }
}
pub fn slice_to(&self, end: usize) -> Self {
self.check_index(end);
unsafe { Self::from_bytes_unchecked(self.bytes.slice_to(end)) }
}
pub fn split_off(&mut self, mid: usize) -> Self {
self.check_index(mid);
unsafe { Self::from_bytes_unchecked(self.bytes.split_off(mid)) }
}
pub fn split_to(&mut self, mid: usize) -> Self {
self.check_index(mid);
unsafe { Self::from_bytes_unchecked(self.bytes.split_to(mid)) }
}
pub fn truncate(&mut self, len: usize) {
self.check_index(len);
self.bytes.truncate(len);
}
pub fn split_first(&mut self) -> Option<Self> {
if self.is_empty() {
return None
}
let first_end = match self.iter().next() {
Some(label) => label.len() + 1,
None => return None
};
Some(unsafe {
Self::from_bytes_unchecked(self.bytes.split_to(first_end))
})
}
pub fn parent(&mut self) -> bool {
self.split_first().is_some()
}
pub fn strip_suffix<N: ToRelativeDname>(&mut self, base: &N)
-> Result<(), StripSuffixError> {
if self.ends_with(base) {
let idx = self.bytes.len() - base.compose_len();
self.bytes.split_off(idx);
Ok(())
}
else {
Err(StripSuffixError)
}
}
}
impl Compose for RelativeDname {
fn compose_len(&self) -> usize {
self.bytes.len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(self.as_ref())
}
}
impl<'a> ToLabelIter<'a> for RelativeDname {
type LabelIter = DnameIter<'a>;
fn iter_labels(&'a self) -> Self::LabelIter {
self.iter()
}
}
impl ToRelativeDname for RelativeDname {
fn to_name(&self) -> RelativeDname {
self.clone()
}
fn as_flat_slice(&self) -> Option<&[u8]> {
Some(self.as_slice())
}
}
impl ops::Deref for RelativeDname {
type Target = Bytes;
fn deref(&self) -> &Bytes {
self.as_ref()
}
}
impl AsRef<Bytes> for RelativeDname {
fn as_ref(&self) -> &Bytes {
&self.bytes
}
}
impl AsRef<[u8]> for RelativeDname {
fn as_ref(&self) -> &[u8] {
self.bytes.as_ref()
}
}
impl<'a> IntoIterator for &'a RelativeDname {
type Item = &'a Label;
type IntoIter = DnameIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<N: ToRelativeDname> PartialEq<N> for RelativeDname {
fn eq(&self, other: &N) -> bool {
self.name_eq(other)
}
}
impl Eq for RelativeDname { }
impl PartialOrd for RelativeDname {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.name_cmp(other))
}
}
impl Ord for RelativeDname {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.name_cmp(other)
}
}
impl hash::Hash for RelativeDname {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
for item in self.iter() {
item.hash(state)
}
}
}
impl fmt::Display for RelativeDname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.iter();
match iter.next() {
Some(label) => label.fmt(f)?,
None => return Ok(())
}
for label in iter {
f.write_str(".")?;
label.fmt(f)?;
}
Ok(())
}
}
impl fmt::Debug for RelativeDname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RelativeDname({})", self)
}
}
#[derive(Clone, Debug)]
pub struct DnameIter<'a> {
slice: &'a [u8],
}
impl<'a> DnameIter<'a> {
pub(super) fn new(slice: &'a [u8]) -> Self {
DnameIter { slice }
}
}
impl<'a> Iterator for DnameIter<'a> {
type Item = &'a Label;
fn next(&mut self) -> Option<Self::Item> {
let (label, tail) = match Label::split_from(self.slice) {
Ok(res) => res,
Err(_) => return None,
};
self.slice = tail;
Some(label)
}
}
impl<'a> DoubleEndedIterator for DnameIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.slice.is_empty() {
return None
}
let mut tmp = self.slice;
loop {
let (label, tail) = Label::split_from(tmp).unwrap();
if tail.is_empty() {
let end = self.slice.len() - (label.len() + 1);
self.slice = &self.slice[..end];
return Some(label)
}
else {
tmp = tail
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum RelativeDnameError {
#[fail(display="{}", _0)]
BadLabel(LabelTypeError),
#[fail(display="compressed domain name")]
CompressedName,
#[fail(display="unexpected end of input")]
ShortData,
#[fail(display="long domain name")]
LongName,
#[fail(display="absolute domain name")]
AbsoluteName,
}
impl From<LabelTypeError> for RelativeDnameError {
fn from(err: LabelTypeError) -> Self {
RelativeDnameError::BadLabel(err)
}
}
impl From<SplitLabelError> for RelativeDnameError {
fn from(err: SplitLabelError) -> Self {
match err {
SplitLabelError::Pointer(_) => RelativeDnameError::CompressedName,
SplitLabelError::BadType(t) => RelativeDnameError::BadLabel(t),
SplitLabelError::ShortBuf => RelativeDnameError::ShortData,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
#[fail(display="suffix not found")]
pub struct StripSuffixError;
#[cfg(test)]
mod test {
use super::*;
use ::bits::parse::ShortBuf;
macro_rules! assert_panic {
( $cond:expr ) => {
{
let result = ::std::panic::catch_unwind(|| $cond);
assert!(result.is_err());
}
}
}
#[test]
fn empty() {
assert_eq!(RelativeDname::empty().as_slice(), b"");
}
#[test]
fn wildcard() {
assert_eq!(RelativeDname::wildcard().as_slice(), b"\x01*");
}
#[test]
fn from_slice() {
assert_eq!(RelativeDname::from_slice(b"").unwrap().as_slice(), b"");
assert_eq!(RelativeDname::from_slice(b"\x03www").unwrap().as_slice(),
b"\x03www");
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example")
.unwrap().as_slice(),
b"\x03www\x07example");
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example\x03com\0"),
Err(RelativeDnameError::AbsoluteName));
assert_eq!(RelativeDname::from_slice(b"\0"),
Err(RelativeDnameError::AbsoluteName));
assert_eq!(Dname::from_slice(b"\x03www\x07exa"),
Err(ShortBuf.into()));
let mut slice = [0u8; 64];
slice[0] = 63;
assert!(RelativeDname::from_slice(&slice[..]).is_ok());
let mut slice = [0u8; 65];
slice[0] = 64;
assert!(RelativeDname::from_slice(&slice[..]).is_err());
let mut buf = Vec::new();
for _ in 0..25 {
buf.extend_from_slice(b"\x09123456789");
}
assert_eq!(buf.len(), 250);
let mut tmp = buf.clone();
tmp.extend_from_slice(b"\x03123");
assert_eq!(RelativeDname::from_slice(&tmp).map(|_| ()), Ok(()));
buf.extend_from_slice(b"\x041234");
assert!(RelativeDname::from_slice(&buf).is_err());
assert_eq!(RelativeDname::from_slice(b"\xa2asdasds"),
Err(LabelTypeError::Undefined.into()));
assert_eq!(RelativeDname::from_slice(b"\x62asdasds"),
Err(LabelTypeError::Extended(0x62).into()));
assert_eq!(RelativeDname::from_slice(b"\xccasdasds"),
Err(RelativeDnameError::CompressedName.into()));
}
#[test]
fn into_absolute() {
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap().into_absolute().as_slice(),
b"\x03www\x07example\x03com\0");
}
#[test]
fn chain_root() {
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap().chain_root());
}
#[test]
fn iter() {
use ::bits::name::dname::test::cmp_iter;
cmp_iter(RelativeDname::empty().iter(), &[]);
cmp_iter(RelativeDname::wildcard().iter(), &[b"*"]);
cmp_iter(RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap().iter(),
&[b"www", b"example", b"com"]);
}
#[test]
fn iter_back() {
use ::bits::name::dname::test::cmp_iter_back;
cmp_iter_back(RelativeDname::empty().iter(), &[]);
cmp_iter_back(RelativeDname::wildcard().iter(), &[b"*"]);
cmp_iter_back(RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap().iter(),
&[b"com", b"example", b"www"]);
}
#[test]
fn label_count() {
assert_eq!(RelativeDname::empty().label_count(), 0);
assert_eq!(RelativeDname::wildcard().label_count(), 1);
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap().label_count(),
3);
}
#[test]
fn first() {
assert_eq!(RelativeDname::empty().first(), None);
assert_eq!(RelativeDname::from_slice(b"\x03www").unwrap()
.first().unwrap().as_slice(),
b"www");
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example").unwrap()
.first().unwrap().as_slice(),
b"www");
}
#[test]
fn last() {
assert_eq!(RelativeDname::empty().last(), None);
assert_eq!(RelativeDname::from_slice(b"\x03www").unwrap()
.last().unwrap().as_slice(),
b"www");
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example").unwrap()
.last().unwrap().as_slice(),
b"example");
}
#[test]
fn ndots() {
assert_eq!(RelativeDname::empty().ndots(), 0);
assert_eq!(RelativeDname::from_slice(b"\x03www").unwrap().ndots(),
0);
assert_eq!(RelativeDname::from_slice(b"\x03www\x07example").unwrap()
.ndots(),
1);
}
#[test]
fn starts_with() {
let matrix = [
( RelativeDname::empty(),
[ true, false, false, false, false, false ]),
( RelativeDname::from_slice(b"\x03www").unwrap(),
[ true, true, false, false, false, false ]),
( RelativeDname::from_slice(b"\x03www\x07example").unwrap(),
[ true, true, true, false, false, false ]),
( RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
[ true, true, true, true, false, false ]),
( RelativeDname::from_slice(b"\x07example\x03com").unwrap(),
[ true, false, false, false, true, false ]),
( RelativeDname::from_slice(b"\x03com").unwrap(),
[ true, false, false, false, false, true ])
];
for i in 0..6 {
for j in 0..6 {
assert_eq!(matrix[i].0.starts_with(&matrix[j].0),
matrix[i].1[j],
"i={}, j={}", i, j)
}
}
}
#[test]
fn ends_with() {
let matrix = [
( RelativeDname::empty(),
[ true, false, false, false, false, false ]),
( RelativeDname::from_slice(b"\x03www").unwrap(),
[ true, true, false, false, false, false ]),
( RelativeDname::from_slice(b"\x03www\x07example").unwrap(),
[ true, false, true, false, false, false ]),
( RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
[ true, false, false, true, true, true]),
( RelativeDname::from_slice(b"\x07example\x03com").unwrap(),
[ true, false, false, false, true, true]),
( RelativeDname::from_slice(b"\x03com").unwrap(),
[ true, false, false, false, false, true ]),
];
for i in 0..matrix.len() {
for j in 0..matrix.len() {
assert_eq!(matrix[i].0.ends_with(&matrix[j].0),
matrix[i].1[j],
"i={}, j={}", i, j)
}
}
}
#[test]
fn is_label_start() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert!( wec.is_label_start(0)); assert!(!wec.is_label_start(1)); assert!(!wec.is_label_start(2)); assert!(!wec.is_label_start(3)); assert!( wec.is_label_start(4)); assert!(!wec.is_label_start(5)); assert!(!wec.is_label_start(6)); assert!(!wec.is_label_start(7)); assert!(!wec.is_label_start(8)); assert!(!wec.is_label_start(9)); assert!(!wec.is_label_start(10)); assert!(!wec.is_label_start(11)); assert!( wec.is_label_start(12)); assert!(!wec.is_label_start(13)); assert!(!wec.is_label_start(14)); assert!(!wec.is_label_start(15)); assert!( wec.is_label_start(16)); assert!(!wec.is_label_start(17)); }
#[test]
fn slice() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert_eq!(wec.slice(0, 4).as_slice(), b"\x03www");
assert_eq!(wec.slice(0, 12).as_slice(), b"\x03www\x07example");
assert_eq!(wec.slice(4, 12).as_slice(), b"\x07example");
assert_eq!(wec.slice(4, 16).as_slice(), b"\x07example\x03com");
assert_panic!(wec.slice(0,3));
assert_panic!(wec.slice(1,4));
assert_panic!(wec.slice(0,11));
assert_panic!(wec.slice(1,12));
assert_panic!(wec.slice(0,17));
assert_panic!(wec.slice(4,17));
assert_panic!(wec.slice(0,18));
}
#[test]
fn slice_from() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert_eq!(wec.slice_from(0).as_slice(),
b"\x03www\x07example\x03com");
assert_eq!(wec.slice_from(4).as_slice(), b"\x07example\x03com");
assert_eq!(wec.slice_from(12).as_slice(), b"\x03com");
assert_eq!(wec.slice_from(16).as_slice(), b"");
assert_panic!(wec.slice_from(17));
assert_panic!(wec.slice_from(18));
}
#[test]
fn slice_to() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert_eq!(wec.slice_to(0).as_slice(), b"");
assert_eq!(wec.slice_to(4).as_slice(), b"\x03www");
assert_eq!(wec.slice_to(12).as_slice(), b"\x03www\x07example");
assert_eq!(wec.slice_to(16).as_slice(), b"\x03www\x07example\x03com");
assert_panic!(wec.slice_to(17));
assert_panic!(wec.slice_to(18));
}
#[test]
fn split_off() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
let mut tmp = wec.clone();
assert_eq!(tmp.split_off(0).as_slice(), b"\x03www\x07example\x03com");
assert_eq!(tmp.as_slice(), b"");
let mut tmp = wec.clone();
assert_eq!(tmp.split_off(4).as_slice(), b"\x07example\x03com");
assert_eq!(tmp.as_slice(), b"\x03www");
let mut tmp = wec.clone();
assert_eq!(tmp.split_off(12).as_slice(), b"\x03com");
assert_eq!(tmp.as_slice(), b"\x03www\x07example");
let mut tmp = wec.clone();
assert_eq!(tmp.split_off(16).as_slice(), b"");
assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
assert_panic!(wec.clone().split_off(1));
assert_panic!(wec.clone().split_off(14));
assert_panic!(wec.clone().split_off(17));
assert_panic!(wec.clone().split_off(18));
}
#[test]
fn split_to() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
let mut tmp = wec.clone();
assert_eq!(tmp.split_to(0).as_slice(), b"");
assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
let mut tmp = wec.clone();
assert_eq!(tmp.split_to(4).as_slice(), b"\x03www");
assert_eq!(tmp.as_slice(), b"\x07example\x03com");
let mut tmp = wec.clone();
assert_eq!(tmp.split_to(12).as_slice(), b"\x03www\x07example");
assert_eq!(tmp.as_slice(), b"\x03com");
let mut tmp = wec.clone();
assert_eq!(tmp.split_to(16).as_slice(), b"\x03www\x07example\x03com");
assert_eq!(tmp.as_slice(), b"");
assert_panic!(wec.clone().split_to(1));
assert_panic!(wec.clone().split_to(14));
assert_panic!(wec.clone().split_to(17));
assert_panic!(wec.clone().split_to(18));
}
#[test]
fn truncate() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
let mut tmp = wec.clone();
tmp.truncate(0);
assert_eq!(tmp.as_slice(), b"");
let mut tmp = wec.clone();
tmp.truncate(4);
assert_eq!(tmp.as_slice(), b"\x03www");
let mut tmp = wec.clone();
tmp.truncate(12);
assert_eq!(tmp.as_slice(), b"\x03www\x07example");
let mut tmp = wec.clone();
tmp.truncate(16);
assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
assert_panic!(wec.clone().truncate(1));
assert_panic!(wec.clone().truncate(14));
assert_panic!(wec.clone().truncate(17));
assert_panic!(wec.clone().truncate(18));
}
#[test]
fn split_first() {
let mut wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert_eq!(wec.split_first().unwrap().as_slice(), b"\x03www");
assert_eq!(wec.as_slice(), b"\x07example\x03com");
assert_eq!(wec.split_first().unwrap().as_slice(), b"\x07example");
assert_eq!(wec.as_slice(), b"\x03com");
assert_eq!(wec.split_first().unwrap().as_slice(), b"\x03com");
assert_eq!(wec.as_slice(), b"");
assert!(wec.split_first().is_none());
assert_eq!(wec.as_slice(), b"");
assert!(wec.split_first().is_none());
assert_eq!(wec.as_slice(), b"");
}
#[test]
fn parent() {
let mut wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert!(wec.parent());
assert_eq!(wec.as_slice(), b"\x07example\x03com");
assert!(wec.parent());
assert_eq!(wec.as_slice(), b"\x03com");
assert!(wec.parent());
assert_eq!(wec.as_slice(), b"");
assert!(!wec.parent());
assert_eq!(wec.as_slice(), b"");
assert!(!wec.parent());
assert_eq!(wec.as_slice(), b"");
}
#[test]
fn strip_suffix() {
let wec = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
let ec = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
let c = RelativeDname::from_slice(b"\x03com").unwrap();
let wen = RelativeDname::from_slice(b"\x03www\x07example\x03net")
.unwrap();
let en = RelativeDname::from_slice(b"\x07example\x03net").unwrap();
let n = RelativeDname::from_slice(b"\x03net").unwrap();
let mut tmp = wec.clone();
assert_eq!(tmp.strip_suffix(&wec), Ok(()));
assert_eq!(tmp.as_slice(), b"");
let mut tmp = wec.clone();
assert_eq!(tmp.strip_suffix(&ec), Ok(()));
assert_eq!(tmp.as_slice(), b"\x03www");
let mut tmp = wec.clone();
assert_eq!(tmp.strip_suffix(&c), Ok(()));
assert_eq!(tmp.as_slice(), b"\x03www\x07example");
let mut tmp = wec.clone();
assert_eq!(tmp.strip_suffix(&RelativeDname::empty()), Ok(()));
assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com");
assert_eq!(wec.clone().strip_suffix(&wen), Err(StripSuffixError));
assert_eq!(wec.clone().strip_suffix(&en), Err(StripSuffixError));
assert_eq!(wec.clone().strip_suffix(&n), Err(StripSuffixError));
}
#[test]
fn eq() {
assert_eq!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap()
);
assert_eq!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com").unwrap()
);
assert_eq!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03www").unwrap()
.chain(RelativeDname::from_slice(b"\x07example\x03com")
.unwrap())
.unwrap()
);
assert_eq!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03wWw").unwrap()
.chain(RelativeDname::from_slice(b"\x07eXAMple\x03coM")
.unwrap())
.unwrap()
);
assert_ne!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03ww4\x07example\x03com").unwrap()
);
assert_ne!(
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap(),
RelativeDname::from_slice(b"\x03www").unwrap()
.chain(RelativeDname::from_slice(b"\x073xample\x03com")
.unwrap())
.unwrap()
);
}
#[test]
fn cmp() {
use std::cmp::Ordering;
let names = [
RelativeDname::from_slice(b"\x07example").unwrap(),
RelativeDname::from_slice(b"\x01a\x07example").unwrap(),
RelativeDname::from_slice(b"\x08yljkjljk\x01a\x07example").unwrap(),
RelativeDname::from_slice(b"\x01Z\x01a\x07example").unwrap(),
RelativeDname::from_slice(b"\x04zABC\x01a\x07example").unwrap(),
RelativeDname::from_slice(b"\x01z\x07example").unwrap(),
RelativeDname::from_slice(b"\x01\x01\x01z\x07example").unwrap(),
RelativeDname::from_slice(b"\x01*\x01z\x07example").unwrap(),
RelativeDname::from_slice(b"\x01\xc8\x01z\x07example").unwrap(),
];
for i in 0..names.len() {
for j in 0..names.len() {
let ord = if i < j { Ordering::Less }
else if i == j { Ordering::Equal }
else { Ordering::Greater };
assert_eq!(names[i].partial_cmp(&names[j]), Some(ord));
assert_eq!(names[i].cmp(&names[j]), ord);
}
}
let n1 = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
let n2 = RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com")
.unwrap();
assert_eq!(n1.partial_cmp(&n2), Some(Ordering::Equal));
assert_eq!(n1.cmp(&n2), Ordering::Equal);
}
#[test]
fn hash() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut s1 = DefaultHasher::new();
let mut s2 = DefaultHasher::new();
RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap()
.hash(&mut s1);
RelativeDname::from_slice(b"\x03wWw\x07eXAMple\x03Com").unwrap()
.hash(&mut s2);
assert_eq!(s1.finish(), s2.finish());
}
}