use std::{cmp, fmt, hash, ops, str};
use bytes::{BufMut, Bytes};
use ::bits::compose::{Compose, Compress, Compressor};
use ::bits::parse::{Parse, ParseAll, Parser, ShortBuf};
use ::master::scan::{CharSource, Scan, Scanner, ScanError, SyntaxError};
use super::label::{Label, LabelTypeError, SplitLabelError};
use super::relative::{RelativeDname, DnameIter};
use super::traits::{ToLabelIter, ToDname};
use super::uncertain::{UncertainDname, FromStrError};
#[derive(Clone)]
pub struct Dname {
bytes: Bytes
}
impl Dname {
pub(super) unsafe fn from_bytes_unchecked(bytes: Bytes) -> Self {
Dname { bytes }
}
pub fn root() -> Self {
unsafe { Self::from_bytes_unchecked(Bytes::from_static(b"\0")) }
}
pub fn from_bytes(bytes: Bytes) -> Result<Self, DnameBytesError> {
if bytes.len() > 255 {
return Err(DnameError::LongName.into());
}
{
let mut tmp = bytes.as_ref();
loop {
let (label, tail) = Label::split_from(tmp)?;
if label.is_root() {
if tail.is_empty() {
break;
}
else {
return Err(DnameBytesError::TrailingData)
}
}
if tail.is_empty() {
return Err(DnameBytesError::RelativeName)
}
tmp = tail;
}
}
Ok(unsafe { Dname::from_bytes_unchecked(bytes) })
}
pub fn from_slice(s: &[u8]) -> Result<Self, DnameBytesError> {
Self::from_bytes(s.into())
}
pub fn from_chars<C>(chars: C) -> Result<Self, FromStrError>
where C: IntoIterator<Item=char> {
UncertainDname::from_chars(chars).map(|res| res.into_absolute())
}
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_relative(mut self) -> RelativeDname {
let len = self.bytes.len() - 1;
self.bytes.truncate(len);
unsafe { RelativeDname::from_bytes_unchecked(self.bytes) }
}
}
impl Dname {
pub fn is_root(&self) -> bool {
self.len() == 1
}
}
impl Dname {
pub fn iter(&self) -> DnameIter {
DnameIter::new(self.bytes.as_ref())
}
pub fn iter_suffixes(&self) -> SuffixIter {
SuffixIter::new(self)
}
pub fn label_count(&self) -> usize {
self.iter().count()
}
pub fn first(&self) -> &Label {
self.iter().next().unwrap()
}
pub fn last(&self) -> &'static Label {
Label::root()
}
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 || len == 1 { 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) -> RelativeDname {
self.check_index(begin);
self.check_index(end);
unsafe {
RelativeDname::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) -> RelativeDname {
self.check_index(end);
unsafe {
RelativeDname::from_bytes_unchecked(self.bytes.slice_to(end))
}
}
pub fn split_off(mut self, mid: usize) -> (RelativeDname, Dname) {
let left = self.split_to(mid);
(left, self)
}
pub fn split_to(&mut self, mid: usize) -> RelativeDname {
self.check_index(mid);
unsafe {
RelativeDname::from_bytes_unchecked(self.bytes.split_to(mid))
}
}
pub fn truncate(mut self, len: usize) -> RelativeDname {
self.check_index(len);
self.bytes.truncate(len);
unsafe { RelativeDname::from_bytes_unchecked(self.bytes) }
}
pub fn split_first(&mut self) -> Option<RelativeDname> {
if self.len() == 1 {
return None
}
let end = self.iter().next().unwrap().len() + 1;
Some(unsafe {
RelativeDname::from_bytes_unchecked(self.bytes.split_to(end))
})
}
pub fn parent(&mut self) -> bool {
self.split_first().is_some()
}
pub fn strip_suffix<N: ToDname>(self, base: &N)
-> Result<RelativeDname, Dname> {
if self.ends_with(base) {
let len = self.compose_len() - base.compose_len();
Ok(self.truncate(len))
}
else {
Err(self)
}
}
}
impl Parse for Dname {
type Err = DnameParseError;
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
let len = name_len(parser)?;
Ok(unsafe {
Self::from_bytes_unchecked(parser.parse_bytes(len).unwrap())
})
}
fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
let len = name_len(parser)?;
parser.advance(len)?;
Ok(())
}
}
fn name_len(parser: &mut Parser) -> Result<usize, DnameParseError> {
let len = {
let mut tmp = parser.peek_all();
loop {
if tmp.is_empty() {
return Err(ShortBuf.into())
}
let (label, tail) = Label::split_from(tmp)?;
tmp = tail;
if label.is_root() {
break;
}
}
parser.remaining() - tmp.len()
};
if len > 255 {
Err(DnameError::LongName.into())
}
else {
Ok(len)
}
}
impl ParseAll for Dname {
type Err = DnameBytesError;
fn parse_all(parser: &mut Parser, len: usize) -> Result<Self, Self::Err> {
Self::from_bytes(parser.parse_bytes(len)?)
}
}
impl Compose for Dname {
fn compose_len(&self) -> usize {
self.bytes.len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(self.as_ref())
}
}
impl Compress for Dname {
fn compress(&self, compressor: &mut Compressor) -> Result<(), ShortBuf> {
compressor.compress_name(self)
}
}
impl str::FromStr for Dname {
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
UncertainDname::from_str(s).map(|res| res.into_absolute())
}
}
impl<'a> ToLabelIter<'a> for Dname {
type LabelIter = DnameIter<'a>;
fn iter_labels(&'a self) -> Self::LabelIter {
self.iter()
}
}
impl ToDname for Dname {
fn to_name(&self) -> Dname {
self.clone()
}
fn as_flat_slice(&self) -> Option<&[u8]> {
Some(self.as_slice())
}
}
impl ops::Deref for Dname {
type Target = Bytes;
fn deref(&self) -> &Bytes {
self.as_ref()
}
}
impl AsRef<Bytes> for Dname {
fn as_ref(&self) -> &Bytes {
&self.bytes
}
}
impl AsRef<[u8]> for Dname {
fn as_ref(&self) -> &[u8] {
self.bytes.as_ref()
}
}
impl<'a> IntoIterator for &'a Dname {
type Item = &'a Label;
type IntoIter = DnameIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<N: ToDname> PartialEq<N> for Dname {
fn eq(&self, other: &N) -> bool {
self.name_eq(other)
}
}
impl Eq for Dname { }
impl<N: ToDname> PartialOrd<N> for Dname {
fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
Some(self.name_cmp(other))
}
}
impl Ord for Dname {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.name_cmp(other)
}
}
impl hash::Hash for Dname {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
for item in self.iter() {
item.hash(state)
}
}
}
impl Scan for Dname {
fn scan<C: CharSource>(scanner: &mut Scanner<C>)
-> Result<Self, ScanError> {
let pos = scanner.pos();
let name = match UncertainDname::scan(scanner)? {
UncertainDname::Relative(name) => name,
UncertainDname::Absolute(name) => return Ok(name)
};
let origin = match *scanner.origin() {
Some(ref origin) => origin,
None => return Err((SyntaxError::NoOrigin, pos).into())
};
name.into_builder().append_origin(origin)
.map_err(|err| (SyntaxError::from(err), pos).into())
}
}
impl fmt::Display for Dname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.iter();
write!(f, "{}", iter.next().unwrap())?;
for label in iter {
if !label.is_root() {
write!(f, ".{}", label)?
}
}
Ok(())
}
}
impl fmt::Debug for Dname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Dname({}.)", self)
}
}
#[derive(Clone, Debug)]
pub struct SuffixIter {
name: Option<Dname>,
}
impl SuffixIter {
fn new(name: &Dname) -> Self {
SuffixIter {
name: Some(name.clone())
}
}
}
impl Iterator for SuffixIter {
type Item = Dname;
fn next(&mut self) -> Option<Self::Item> {
let (res, ok) = match self.name {
Some(ref mut name) => (name.clone(), name.parent()),
None => return None
};
if !ok {
self.name = None
}
Some(res)
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum DnameError {
#[fail(display="{}", _0)]
BadLabel(LabelTypeError),
#[fail(display="compressed domain name")]
CompressedName,
#[fail(display="long domain name")]
LongName,
}
impl From<LabelTypeError> for DnameError {
fn from(err: LabelTypeError) -> DnameError {
DnameError::BadLabel(err)
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum DnameParseError {
#[fail(display="{}", _0)]
BadName(DnameError),
#[fail(display="unexpected end of buffer")]
ShortBuf,
}
impl<T: Into<DnameError>> From<T> for DnameParseError {
fn from(err: T) -> DnameParseError {
DnameParseError::BadName(err.into())
}
}
impl From<SplitLabelError> for DnameParseError {
fn from(err: SplitLabelError) -> DnameParseError {
match err {
SplitLabelError::Pointer(_)
=> DnameParseError::BadName(DnameError::CompressedName),
SplitLabelError::BadType(t)
=> DnameParseError::BadName(DnameError::BadLabel(t)),
SplitLabelError::ShortBuf => DnameParseError::ShortBuf,
}
}
}
impl From<ShortBuf> for DnameParseError {
fn from(_: ShortBuf) -> DnameParseError {
DnameParseError::ShortBuf
}
}
#[derive(Clone, Copy, Debug, Eq, Fail, PartialEq)]
pub enum DnameBytesError {
#[fail(display="{}", _0)]
ParseError(DnameParseError),
#[fail(display="relative name")]
RelativeName,
#[fail(display="trailing data")]
TrailingData,
}
impl<T: Into<DnameParseError>> From<T> for DnameBytesError {
fn from(err: T) -> DnameBytesError {
DnameBytesError::ParseError(err.into())
}
}
#[cfg(test)]
pub(crate) mod test {
use std::cmp::Ordering;
use super::*;
macro_rules! assert_panic {
( $cond:expr ) => {
{
let result = ::std::panic::catch_unwind(|| $cond);
assert!(result.is_err());
}
}
}
#[test]
fn root() {
assert_eq!(Dname::root().as_slice(), b"\0");
}
#[test]
fn from_slice() {
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com"),
Err(DnameBytesError::RelativeName));
assert_eq!(Dname::from_slice(b"\x03www\x07exa"),
Err(ShortBuf.into()));
let mut slice = [0u8; 65];
slice[0] = 63;
assert!(Dname::from_slice(&slice[..]).is_ok());
let mut slice = [0u8; 66];
slice[0] = 64;
assert!(Dname::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\0");
assert_eq!(Dname::from_slice(&tmp).map(|_| ()), Ok(()));
buf.extend_from_slice(b"\x041234\0");
assert!(Dname::from_slice(&buf).is_err());
assert!(Dname::from_slice(b"\x03com\0\x03www\0").is_err());
assert_eq!(Dname::from_slice(b"\xa2asdasds"),
Err(LabelTypeError::Undefined.into()));
assert_eq!(Dname::from_slice(b"\x62asdasds"),
Err(LabelTypeError::Extended(0x62).into()));
assert_eq!(Dname::from_slice(b"\xccasdasds"),
Err(DnameError::CompressedName.into()));
assert_eq!(Dname::from_slice(b""), Err(ShortBuf.into()));
}
#[test]
fn into_relative() {
assert_eq!(Dname::from_slice(b"\x03www\0").unwrap()
.into_relative().as_slice(),
b"\x03www");
}
#[test]
fn is_root() {
assert_eq!(Dname::from_slice(b"\0").unwrap().is_root(), true);
assert_eq!(Dname::from_slice(b"\x03www\0").unwrap().is_root(), false);
assert_eq!(Dname::root().is_root(), true);
}
pub fn cmp_iter<I>(mut iter: I, labels: &[&[u8]])
where
I: Iterator,
I::Item: AsRef<[u8]>
{
let mut labels = labels.iter();
loop {
match (iter.next(), labels.next()) {
(Some(left), Some(right)) => assert_eq!(left.as_ref(), *right),
(None, None) => break,
(_, None) => panic!("extra items in iterator"),
(None, _) => panic!("missing items in iterator"),
}
}
}
#[test]
fn iter() {
cmp_iter(Dname::root().iter(), &[b""]);
cmp_iter(Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap().iter(),
&[b"www", b"example", b"com", b""]);
}
pub fn cmp_iter_back<I>(mut iter: I, labels: &[&[u8]])
where
I: DoubleEndedIterator,
I::Item: AsRef<[u8]>
{
let mut labels = labels.iter();
loop {
match (iter.next_back(), labels.next()) {
(Some(left), Some(right)) => assert_eq!(left.as_ref(), *right),
(None, None) => break,
(_, None) => panic!("extra items in iterator"),
(None, _) => panic!("missing items in iterator"),
}
}
}
#[test]
fn iter_back() {
cmp_iter_back(Dname::root().iter(), &[b""]);
cmp_iter_back(Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap().iter(),
&[b"", b"com", b"example", b"www"]);
}
#[test]
fn iter_suffixes() {
cmp_iter(Dname::root().iter_suffixes(), &[b"\0"]);
cmp_iter(Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap().iter_suffixes(),
&[b"\x03www\x07example\x03com\0", b"\x07example\x03com\0",
b"\x03com\0", b"\0"]);
}
#[test]
fn label_count() {
assert_eq!(Dname::root().label_count(), 1);
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
.label_count(),
4);
}
#[test]
fn first() {
assert_eq!(Dname::root().first().as_slice(), b"");
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
.first().as_slice(),
b"www");
}
#[test]
fn last() {
assert_eq!(Dname::root().last().as_slice(), b"");
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
.last().as_slice(),
b"");
}
#[test]
fn starts_with() {
let root = Dname::root();
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert!(root.starts_with(&root));
assert!(wecr.starts_with(&wecr));
assert!( root.starts_with(&RelativeDname::empty()));
assert!( wecr.starts_with(&RelativeDname::empty()));
let test = RelativeDname::from_slice(b"\x03www").unwrap();
assert!(!root.starts_with(&test));
assert!( wecr.starts_with(&test));
let test = RelativeDname::from_slice(b"\x03www\x07example").unwrap();
assert!(!root.starts_with(&test));
assert!( wecr.starts_with(&test));
let test = RelativeDname::from_slice(b"\x03www\x07example\x03com")
.unwrap();
assert!(!root.starts_with(&test));
assert!( wecr.starts_with(&test));
let test = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
assert!(!root.starts_with(&test));
assert!(!wecr.starts_with(&test));
let test = RelativeDname::from_slice(b"\x03www").unwrap()
.chain(RelativeDname::from_slice(b"\x07example").unwrap())
.unwrap();
assert!(!root.starts_with(&test));
assert!( wecr.starts_with(&test));
let test = test.chain(RelativeDname::from_slice(b"\x03com")
.unwrap())
.unwrap();
assert!(!root.starts_with(&test));
assert!( wecr.starts_with(&test));
}
#[test]
fn ends_with() {
let root = Dname::root();
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
for name in wecr.iter_suffixes() {
if name.is_root() {
assert!(root.ends_with(&name));
}
else {
assert!(!root.ends_with(&name));
}
assert!(wecr.ends_with(&name));
}
}
#[test]
fn is_label_start() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert!( wecr.is_label_start(0)); assert!(!wecr.is_label_start(1)); assert!(!wecr.is_label_start(2)); assert!(!wecr.is_label_start(3)); assert!( wecr.is_label_start(4)); assert!(!wecr.is_label_start(5)); assert!(!wecr.is_label_start(6)); assert!(!wecr.is_label_start(7)); assert!(!wecr.is_label_start(8)); assert!(!wecr.is_label_start(9)); assert!(!wecr.is_label_start(10)); assert!(!wecr.is_label_start(11)); assert!( wecr.is_label_start(12)); assert!(!wecr.is_label_start(13)); assert!(!wecr.is_label_start(14)); assert!(!wecr.is_label_start(15)); assert!( wecr.is_label_start(16)); assert!(!wecr.is_label_start(17)); assert!(!wecr.is_label_start(18)); }
#[test]
fn slice() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert_eq!(wecr.slice(0, 4).as_slice(), b"\x03www");
assert_eq!(wecr.slice(0, 12).as_slice(), b"\x03www\x07example");
assert_eq!(wecr.slice(4, 12).as_slice(), b"\x07example");
assert_eq!(wecr.slice(4, 16).as_slice(), b"\x07example\x03com");
assert_panic!(wecr.slice(0,3));
assert_panic!(wecr.slice(1,4));
assert_panic!(wecr.slice(0,11));
assert_panic!(wecr.slice(1,12));
assert_panic!(wecr.slice(0,17));
assert_panic!(wecr.slice(4,17));
assert_panic!(wecr.slice(0,18));
}
#[test]
fn slice_from() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert_eq!(wecr.slice_from(0).as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(wecr.slice_from(4).as_slice(), b"\x07example\x03com\0");
assert_eq!(wecr.slice_from(12).as_slice(), b"\x03com\0");
assert_eq!(wecr.slice_from(16).as_slice(), b"\0");
assert_panic!(wecr.slice_from(17));
assert_panic!(wecr.slice_from(18));
}
#[test]
fn slice_to() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert_eq!(wecr.slice_to(0).as_slice(), b"");
assert_eq!(wecr.slice_to(4).as_slice(), b"\x03www");
assert_eq!(wecr.slice_to(12).as_slice(), b"\x03www\x07example");
assert_eq!(wecr.slice_to(16).as_slice(), b"\x03www\x07example\x03com");
assert_panic!(wecr.slice_to(17));
assert_panic!(wecr.slice_to(18));
}
#[test]
fn split_off() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
let (left, right) = wecr.clone().split_off(0);
assert_eq!(left.as_slice(), b"");
assert_eq!(right.as_slice(), b"\x03www\x07example\x03com\0");
let (left, right) = wecr.clone().split_off(4);
assert_eq!(left.as_slice(), b"\x03www");
assert_eq!(right.as_slice(), b"\x07example\x03com\0");
let (left, right) = wecr.clone().split_off(12);
assert_eq!(left.as_slice(), b"\x03www\x07example");
assert_eq!(right.as_slice(), b"\x03com\0");
let (left, right) = wecr.clone().split_off(16);
assert_eq!(left.as_slice(), b"\x03www\x07example\x03com");
assert_eq!(right.as_slice(), b"\0");
assert_panic!(wecr.clone().split_off(1));
assert_panic!(wecr.clone().split_off(14));
assert_panic!(wecr.clone().split_off(17));
assert_panic!(wecr.clone().split_off(18));
}
#[test]
fn split_to() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
let mut tmp = wecr.clone();
assert_eq!(tmp.split_to(0).as_slice(), b"");
assert_eq!(tmp.as_slice(), b"\x03www\x07example\x03com\0");
let mut tmp = wecr.clone();
assert_eq!(tmp.split_to(4).as_slice(), b"\x03www");
assert_eq!(tmp.as_slice(), b"\x07example\x03com\0");
let mut tmp = wecr.clone();
assert_eq!(tmp.split_to(12).as_slice(), b"\x03www\x07example");
assert_eq!(tmp.as_slice(), b"\x03com\0");
let mut tmp = wecr.clone();
assert_eq!(tmp.split_to(16).as_slice(), b"\x03www\x07example\x03com");
assert_eq!(tmp.as_slice(), b"\0");
assert_panic!(wecr.clone().split_to(1));
assert_panic!(wecr.clone().split_to(14));
assert_panic!(wecr.clone().split_to(17));
assert_panic!(wecr.clone().split_to(18));
}
#[test]
fn truncate() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert_eq!(wecr.clone().truncate(0).as_slice(),
b"");
assert_eq!(wecr.clone().truncate(4).as_slice(),
b"\x03www");
assert_eq!(wecr.clone().truncate(12).as_slice(),
b"\x03www\x07example");
assert_eq!(wecr.clone().truncate(16).as_slice(),
b"\x03www\x07example\x03com");
assert_panic!(wecr.clone().truncate(1));
assert_panic!(wecr.clone().truncate(14));
assert_panic!(wecr.clone().truncate(17));
assert_panic!(wecr.clone().truncate(18));
}
#[test]
fn split_first() {
let mut wecr = Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap();
assert_eq!(wecr.split_first().unwrap().as_slice(), b"\x03www");
assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
assert_eq!(wecr.split_first().unwrap().as_slice(), b"\x07example");
assert_eq!(wecr.as_slice(), b"\x03com\0");
assert_eq!(wecr.split_first().unwrap().as_slice(), b"\x03com");
assert_eq!(wecr.as_slice(), b"\0");
assert!(wecr.split_first().is_none());
assert_eq!(wecr.as_slice(), b"\0");
assert!(wecr.split_first().is_none());
assert_eq!(wecr.as_slice(), b"\0");
}
#[test]
fn parent() {
let mut wecr = Dname::from_slice(b"\x03www\x07example\x03com\0")
.unwrap();
assert!(wecr.parent());
assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
assert!(wecr.parent());
assert_eq!(wecr.as_slice(), b"\x03com\0");
assert!(wecr.parent());
assert_eq!(wecr.as_slice(), b"\0");
assert!(!wecr.parent());
assert_eq!(wecr.as_slice(), b"\0");
assert!(!wecr.parent());
assert_eq!(wecr.as_slice(), b"\0");
}
#[test]
fn strip_suffix() {
let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
let ecr = Dname::from_slice(b"\x07example\x03com\0").unwrap();
let cr = Dname::from_slice(b"\x03com\0").unwrap();
let wenr = Dname::from_slice(b"\x03www\x07example\x03net\0").unwrap();
let enr = Dname::from_slice(b"\x07example\x03net\0").unwrap();
let nr = Dname::from_slice(b"\x03net\0").unwrap();
assert_eq!(wecr.clone().strip_suffix(&wecr).unwrap().as_slice(),
b"");
assert_eq!(wecr.clone().strip_suffix(&ecr).unwrap().as_slice(),
b"\x03www");
assert_eq!(wecr.clone().strip_suffix(&cr).unwrap().as_slice(),
b"\x03www\x07example");
assert_eq!(wecr.clone().strip_suffix(&Dname::root())
.unwrap().as_slice(),
b"\x03www\x07example\x03com");
assert_eq!(wecr.clone().strip_suffix(&wenr).unwrap_err().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(wecr.clone().strip_suffix(&enr).unwrap_err().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(wecr.clone().strip_suffix(&nr).unwrap_err().as_slice(),
b"\x03www\x07example\x03com\0");
}
#[test]
fn parse() {
let mut p = Parser::from_static(b"\x03www\x07example\x03com\0af");
assert_eq!(Dname::parse(&mut p).unwrap().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(p.peek_all(), b"af");
let mut p = Parser::from_static(b"\x03www\x07exam");
assert_eq!(Dname::parse(&mut p), Err(ShortBuf.into()));
let mut p = Parser::from_static(b"\x03www\x07example");
assert_eq!(Dname::parse(&mut p), Err(ShortBuf.into()));
let mut p = Parser::from_static(b"\x03com\x03www\x07example\xc0\0");
p.advance(4).unwrap();
assert_eq!(Dname::parse(&mut p),
Err(DnameError::CompressedName.into()));
let mut p = Parser::from_static(b"\x03www\x07example\xbffoo");
assert_eq!(Dname::parse(&mut p),
Err(LabelTypeError::Undefined.into()));
let mut buf = Vec::new();
for _ in 0..50 {
buf.extend_from_slice(b"\x041234");
}
buf.extend_from_slice(b"\x03123\0");
assert_eq!(buf.len(), 255);
let mut p = Parser::from_bytes(buf.into());
assert!(Dname::parse(&mut p).is_ok());
assert_eq!(p.peek_all(), b"");
let mut buf = Vec::new();
for _ in 0..51 {
buf.extend_from_slice(b"\x041234");
}
buf.extend_from_slice(b"\0");
assert_eq!(buf.len(), 256);
let mut p = Parser::from_bytes(buf.into());
assert_eq!(Dname::parse(&mut p),
Err(DnameError::LongName.into()));
}
#[test]
fn parse_all() {
let mut p = Parser::from_static(b"\x03www\x07example\x03com\0af");
assert_eq!(Dname::parse_all(&mut p, 17).unwrap().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(p.peek_all(), b"af");
let mut p = Parser::from_static(b"\0af");
assert_eq!(Dname::parse_all(&mut p, 1).unwrap().as_slice(), b"\0");
assert_eq!(p.peek_all(), b"af");
}
#[test]
fn from_str() {
use std::str::FromStr;
assert_eq!(Dname::from_str("www.example.com").unwrap().as_slice(),
b"\x03www\x07example\x03com\0");
assert_eq!(Dname::from_str("www.example.com.").unwrap().as_slice(),
b"\x03www\x07example\x03com\0");
}
#[test]
fn eq() {
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap());
assert_eq!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap());
assert_eq!(
Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
RelativeDname::from_slice(b"\x03www").unwrap()
.chain(RelativeDname::from_slice(b"\x07example\x03com")
.unwrap())
.unwrap()
.chain(Dname::root()).unwrap()
);
assert_eq!(
Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
RelativeDname::from_slice(b"\x03wWw").unwrap()
.chain(RelativeDname::from_slice(b"\x07eXAMple\x03coM")
.unwrap())
.unwrap()
.chain(Dname::root()).unwrap()
);
assert_ne!(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
Dname::from_slice(b"\x03ww4\x07example\x03com\0").unwrap());
assert_ne!(
Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
RelativeDname::from_slice(b"\x03www").unwrap()
.chain(RelativeDname::from_slice(b"\x073xample\x03com")
.unwrap())
.unwrap()
.chain(Dname::root()).unwrap()
);
}
#[test]
fn cmp() {
let names = [
Dname::from_slice(b"\x07example\0").unwrap(),
Dname::from_slice(b"\x01a\x07example\0").unwrap(),
Dname::from_slice(b"\x08yljkjljk\x01a\x07example\0").unwrap(),
Dname::from_slice(b"\x01Z\x01a\x07example\0").unwrap(),
Dname::from_slice(b"\x04zABC\x01a\x07example\0").unwrap(),
Dname::from_slice(b"\x01z\x07example\0").unwrap(),
Dname::from_slice(b"\x01\x01\x01z\x07example\0").unwrap(),
Dname::from_slice(b"\x01*\x01z\x07example\0").unwrap(),
Dname::from_slice(b"\x01\xc8\x01z\x07example\0").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 = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
let n2 = Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").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();
Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
.hash(&mut s1);
Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap()
.hash(&mut s2);
assert_eq!(s1.finish(), s2.finish());
}
}