use core::{cmp, fmt, hash};
use super::super::cmp::CanonicalOrd;
use super::super::octets::{
Compose, FormError, OctetsBuilder, OctetsRef, Parse, Parser, ParseError,
ShortBuf
};
use super::dname::Dname;
use super::label::{Label, LabelTypeError};
use super::relative::RelativeDname;
use super::traits::{ToLabelIter, ToDname};
#[derive(Clone, Copy)]
pub struct ParsedDname<Ref> {
parser: Parser<Ref>,
len: usize,
compressed: bool,
}
impl<Ref> ParsedDname<Ref> {
pub fn is_compressed(&self) -> bool {
self.compressed
}
pub fn is_root(&self) -> bool {
self.len == 1
}
}
impl<Ref: AsRef<[u8]>> ParsedDname<Ref> {
pub fn iter(&self) -> ParsedDnameIter {
ParsedDnameIter::new(&self.parser, self.len)
}
pub fn iter_suffixes(&self) -> ParsedSuffixIter<Ref>
where Ref: Clone {
ParsedSuffixIter::new(self.clone())
}
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 split_first(&mut self) -> Option<RelativeDname<Ref::Range>>
where Ref: OctetsRef {
if self.len == 1 {
return None
}
let len = loop {
match LabelType::peek(&mut self.parser).unwrap() {
LabelType::Normal(0) => {
unreachable!()
}
LabelType::Normal(label_len) => {
break label_len + 1
}
LabelType::Compressed(pos) => {
self.parser.seek(pos).unwrap();
}
}
};
self.len -= len;
Some(unsafe {
RelativeDname::from_octets_unchecked(
self.parser.parse_octets(len).unwrap()
)
})
}
pub fn parent(&mut self) -> bool {
if self.len == 1 {
return false
}
let len = loop {
match LabelType::peek(&mut self.parser).unwrap() {
LabelType::Normal(0) => {
unreachable!()
}
LabelType::Normal(label_len) => {
break label_len + 1
}
LabelType::Compressed(pos) => {
self.parser.seek(pos).unwrap();
}
}
};
self.len -= len;
self.parser.advance(len).unwrap();
true
}
}
impl<Ref: AsRef<[u8]>> From<Dname<Ref>> for ParsedDname<Ref> {
fn from(name: Dname<Ref>) -> ParsedDname<Ref> {
let parser = Parser::from_ref(name.into_octets());
ParsedDname {
len: parser.as_slice().len(),
parser,
compressed: false
}
}
}
impl<Ref, N> PartialEq<N> for ParsedDname<Ref>
where
Ref: AsRef<[u8]>,
N: ToDname + ?Sized
{
fn eq(&self, other: &N) -> bool {
self.name_eq(other)
}
}
impl<Ref: AsRef<[u8]>> Eq for ParsedDname<Ref> { }
impl<Ref, N> PartialOrd<N> for ParsedDname<Ref>
where
Ref: AsRef<[u8]>,
N: ToDname + ?Sized
{
fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
Some(self.name_cmp(other))
}
}
impl<Ref: AsRef<[u8]>> Ord for ParsedDname<Ref> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.name_cmp(other)
}
}
impl<Ref, N> CanonicalOrd<N> for ParsedDname<Ref>
where
Ref: AsRef<[u8]>,
N: ToDname + ?Sized
{
fn canonical_cmp(&self, other: &N) -> cmp::Ordering {
self.name_cmp(other)
}
}
impl<Ref: AsRef<[u8]>> hash::Hash for ParsedDname<Ref> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
for item in self.iter() {
item.hash(state)
}
}
}
impl<'a, Ref: AsRef<[u8]>> ToLabelIter<'a> for ParsedDname<Ref> {
type LabelIter = ParsedDnameIter<'a>;
fn iter_labels(&'a self) -> Self::LabelIter {
self.iter()
}
fn len(&self) -> usize {
self.len
}
}
impl<Ref: AsRef<[u8]>> ToDname for ParsedDname<Ref> {
fn as_flat_slice(&self) -> Option<&[u8]> {
if self.compressed {
None
}
else {
Some(self.parser.peek(self.len).unwrap())
}
}
}
impl<'a, Ref: AsRef<[u8]>> IntoIterator for &'a ParsedDname<Ref> {
type Item = &'a Label;
type IntoIter = ParsedDnameIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<Ref> Parse<Ref> for ParsedDname<Ref>
where Ref: AsRef<[u8]> + Clone {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let mut res = parser.clone();
let mut tmp = parser.clone();
let mut ptrs = 0;
let mut len = 0;
let mut compressed = false;
loop {
match LabelType::parse(&mut tmp)? {
LabelType::Normal(0) => {
len += 1;
if len > 255 {
return Err(ParsedDnameError::LongName.into())
}
if ptrs == 0 {
parser.seek(tmp.pos()).unwrap();
}
break;
}
LabelType::Normal(label_len) => {
len += label_len + 1;
tmp.advance(label_len)?;
if len > 255 {
return Err(ParsedDnameError::LongName.into())
}
}
LabelType::Compressed(pos) => {
if ptrs >= 127 {
return Err(
ParsedDnameError::ExcessiveCompression.into()
)
}
if ptrs == 0 {
parser.seek(tmp.pos()).unwrap();
}
if len == 0 {
res.seek(pos)?;
}
else {
compressed = true;
}
ptrs += 1;
tmp.seek(pos)?
}
}
}
Ok(ParsedDname { parser: res, len, compressed })
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
let mut len = 0;
loop {
match LabelType::parse(parser) {
Ok(LabelType::Normal(0)) => {
len += 1;
if len > 255 {
return Err(ParsedDnameError::LongName.into())
}
return Ok(())
}
Ok(LabelType::Normal(label_len)) => {
parser.advance(label_len)?;
len += label_len + 1;
if len > 255 {
return Err(ParsedDnameError::LongName.into())
}
}
Ok(LabelType::Compressed(_)) => {
return Ok(())
}
Err(err) => {
return Err(err)
}
}
}
}
}
impl<Ref: AsRef<[u8]>> Compose for ParsedDname<Ref> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
if self.compressed {
target.append_all(|target| {
for label in self.iter() {
label.compose(target)?
}
Ok(())
})
}
else {
target.append_slice(self.parser.peek(self.len).unwrap())
}
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
for label in self.iter_labels() {
label.compose_canonical(target)?;
}
Ok(())
})
}
}
impl<Ref: AsRef<[u8]>> fmt::Display for ParsedDname<Ref> {
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<Ref: AsRef<[u8]>> fmt::Debug for ParsedDname<Ref> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ParsedDname({}.)", self)
}
}
#[derive(Clone)]
pub struct ParsedDnameIter<'a> {
slice: &'a [u8],
pos: usize,
len: usize,
}
impl<'a> ParsedDnameIter<'a> {
pub(crate) fn new<Ref>(parser: &'a Parser<Ref>, len: usize) -> Self
where Ref: AsRef<[u8]> {
ParsedDnameIter { slice: parser.as_slice(), pos: parser.pos(), len }
}
fn get_label(&mut self) -> &'a Label {
let end = loop {
let ltype = self.slice[self.pos];
self.pos += 1;
match ltype {
0 ..= 0x3F => break self.pos + (ltype as usize),
0xC0 ..= 0xFF => {
self.pos = (self.slice[self.pos] as usize)
| (((ltype as usize) & 0x3F) << 8);
}
_ => panic!("bad label")
}
};
let res = unsafe {
Label::from_slice_unchecked(&self.slice[self.pos..end])
};
self.pos = end;
self.len -= res.len() + 1;
res
}
}
impl<'a> Iterator for ParsedDnameIter<'a> {
type Item = &'a Label;
fn next(&mut self) -> Option<&'a Label> {
if self.len == 0 {
return None
}
Some(self.get_label())
}
}
impl<'a> DoubleEndedIterator for ParsedDnameIter<'a> {
fn next_back(&mut self) -> Option<&'a Label> {
if self.len == 0 {
return None
}
let mut tmp = self.clone();
let label = loop {
let label = tmp.get_label();
if tmp.len == 0 {
break label
}
};
self.len -= label.len() + 1;
Some(label)
}
}
#[derive(Clone)]
pub struct ParsedSuffixIter<Ref> {
name: Option<ParsedDname<Ref>>,
}
impl<Ref> ParsedSuffixIter<Ref> {
fn new(name: ParsedDname<Ref>) -> Self {
ParsedSuffixIter { name: Some(name) }
}
}
impl<Ref: AsRef<[u8]> + Clone> Iterator for ParsedSuffixIter<Ref> {
type Item = ParsedDname<Ref>;
fn next(&mut self) -> Option<Self::Item> {
let name = match self.name {
Some(ref mut name) => name,
None => return None
};
let res = name.clone();
if !name.parent() {
self.name = None
}
Some(res)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum LabelType {
Normal(usize),
Compressed(usize),
}
impl LabelType {
pub fn parse<Ref: AsRef<[u8]>>(
parser: &mut Parser<Ref>
) -> Result<Self, ParseError> {
let ltype = parser.parse_u8()?;
match ltype {
0 ..= 0x3F => Ok(LabelType::Normal(ltype as usize)),
0xC0 ..= 0xFF => {
let res = parser.parse_u8()? as usize;
let res = res | (((ltype as usize) & 0x3F) << 8);
Ok(LabelType::Compressed(res))
}
_ => Err(ParseError::Form(FormError::new("invalid label type")))
}
}
pub fn peek<Ref: AsRef<[u8]>>(
parser: &mut Parser<Ref>
) -> Result<Self, ParseError> {
let ltype = parser.peek(1)?[0];
match ltype {
0 ..= 0x3F => Ok(LabelType::Normal(ltype as usize)),
0xC0 ..= 0xFF => {
let res = (parser.peek(2)?[1]) as usize;
let res = res | (((ltype as usize) & 0x3F) << 8);
Ok(LabelType::Compressed(res))
}
_ => Err(ParseError::Form(FormError::new("invalid label type")))
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ParsedDnameError {
BadLabel(LabelTypeError),
LongName,
ExcessiveCompression,
}
impl fmt::Display for ParsedDnameError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
FormError::from(*self).fmt(f)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParsedDnameError { }
impl From<LabelTypeError> for ParsedDnameError {
fn from(err: LabelTypeError) -> Self {
ParsedDnameError::BadLabel(err)
}
}
impl From<ParsedDnameError> for FormError {
fn from(err: ParsedDnameError) -> FormError {
match err {
ParsedDnameError::BadLabel(_) => {
FormError::new("invalid label type")
}
ParsedDnameError::LongName => FormError::new("long domain name"),
ParsedDnameError::ExcessiveCompression => {
FormError::new("too many compression pointers")
}
}
}
}
impl From<ParsedDnameError> for ParseError {
fn from(err: ParsedDnameError) -> ParseError {
ParseError::Form(err.into())
}
}
#[cfg(test)]
mod test {
use std::vec::Vec;
use crate::base::name::{Dname, RelativeDname};
use super::*;
macro_rules! name {
(root) => {
name!(b"123\0", 3, 1, false)
};
(flat) => {
name!(b"\x03www\x07example\x03com\0\xc0\0", 0, 17, false)
};
(copy) => {
name!(b"\x03www\x07example\x03com\0\xc0\0", 17, 17, false)
};
(once) => {
name!(b"\x03com\0\x03www\x07example\xC0\0", 5, 17, true)
};
(twice) => {
name!(b"\x03com\0\x07example\xc0\0\x03www\xc0\x05", 15, 17, true)
};
($bytes:expr, $start:expr, $len:expr, $compressed:expr) => {
{
let mut parser = Parser::from_ref($bytes.as_ref());
parser.advance($start).unwrap();
ParsedDname { parser, len: $len, compressed: $compressed }
}
}
}
static WECR: &[u8] = b"\x03www\x07example\x03com\0";
#[test]
fn len() {
assert_eq!(name!(root).len(), 1);
assert_eq!(name!(flat).len(), 17);
assert_eq!(name!(once).len(), 17);
assert_eq!(name!(twice).len(), 17);
}
#[test]
fn is_compressed() {
assert_eq!(name!(root).is_compressed(), false);
assert_eq!(name!(flat).is_compressed(), false);
assert_eq!(name!(once).is_compressed(), true);
assert_eq!(name!(twice).is_compressed(), true);
}
#[test]
fn is_root() {
assert_eq!(name!(root).is_root(), true);
assert_eq!(name!(flat).is_root(), false);
assert_eq!(name!(once).is_root(), false);
assert_eq!(name!(twice).is_root(), false);
}
#[test]
fn iter() {
use crate::base::name::dname::test::cmp_iter;
let labels: &[&[u8]] = &[b"www", b"example", b"com", b""];
cmp_iter(name!(root).iter(), &[b""]);
cmp_iter(name!(flat).iter(), labels);
cmp_iter(name!(once).iter(), labels);
cmp_iter(name!(twice).iter(), labels);
}
#[test]
fn iter_back() {
use crate::base::name::dname::test::cmp_iter_back;
let labels: &[&[u8]] = &[b"", b"com", b"example", b"www"];
cmp_iter_back(name!(root).iter(), &[b""]);
cmp_iter_back(name!(flat).iter(), labels);
cmp_iter_back(name!(once).iter(), labels);
cmp_iter_back(name!(twice).iter(), labels);
}
fn cmp_iter_suffixes<I>(iter: I, labels: &[&[u8]])
where I: Iterator<Item=ParsedDname<&'static [u8]>> {
for (name, labels) in iter.zip(labels) {
let mut iter = name.iter();
let labels = Dname::from_slice(labels).unwrap();
let mut labels_iter = labels.iter();
loop {
match (iter.next(), labels_iter.next()) {
(Some(left), Some(right)) => assert_eq!(left, right),
(None, None) => break,
(_, None) => panic!("extra items in iterator"),
(None, _) => panic!("missing items in iterator"),
}
}
}
}
#[test]
fn iter_suffixes() {
let suffixes: &[&[u8]] = &[b"\x03www\x07example\x03com\0",
b"\x07example\x03com\0", b"\x03com\0",
b"\0"];
cmp_iter_suffixes(name!(root).iter_suffixes(), &[b"\0"]);
cmp_iter_suffixes(name!(flat).iter_suffixes(), suffixes);
cmp_iter_suffixes(name!(once).iter_suffixes(), suffixes);
cmp_iter_suffixes(name!(twice).iter_suffixes(), suffixes);
}
#[test]
fn label_count() {
assert_eq!(name!(root).label_count(), 1);
assert_eq!(name!(flat).label_count(), 4);
assert_eq!(name!(once).label_count(), 4);
assert_eq!(name!(twice).label_count(), 4);
}
#[test]
fn first() {
assert_eq!(name!(root).first().as_slice(), b"");
assert_eq!(name!(flat).first().as_slice(), b"www");
assert_eq!(name!(once).first().as_slice(), b"www");
assert_eq!(name!(twice).first().as_slice(), b"www");
}
#[test]
fn starts_with() {
let root = name!(root);
let flat_wec = name!(flat);
let once_wec = name!(once);
let twice_wec = name!(twice);
let test = Dname::root_ref();
assert!( root.starts_with(&test));
assert!(!flat_wec.starts_with(&test));
assert!(!once_wec.starts_with(&test));
assert!(!twice_wec.starts_with(&test));
let test = RelativeDname::empty_ref();
assert!(root.starts_with(&test));
assert!(flat_wec.starts_with(&test));
assert!(once_wec.starts_with(&test));
assert!(twice_wec.starts_with(&test));
let test = RelativeDname::from_slice(b"\x03www").unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
let test = RelativeDname::from_slice(b"\x03www\x07example").unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
let test = RelativeDname::from_slice(
b"\x03www\x07example\x03com"
).unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
let test = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
let test = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
assert!(!root.starts_with(&test));
assert!(!flat_wec.starts_with(&test));
assert!(!once_wec.starts_with(&test));
assert!(!twice_wec.starts_with(&test));
let test = RelativeDname::from_octets(
b"\x03www".as_ref()
).unwrap().chain(
RelativeDname::from_octets(
b"\x07example".as_ref()
).unwrap()
).unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
let test = test.chain(
RelativeDname::from_octets(b"\x03com".as_ref()).unwrap()
).unwrap();
assert!(!root.starts_with(&test));
assert!( flat_wec.starts_with(&test));
assert!( once_wec.starts_with(&test));
assert!( twice_wec.starts_with(&test));
}
#[test]
fn ends_with() {
let root = name!(root);
let flat_wec = name!(flat);
let once_wec = name!(once);
let twice_wec = name!(twice);
let wecr = Dname::from_octets(
b"\x03www\x07example\x03com\0".as_ref()
).unwrap();
for name in wecr.iter_suffixes() {
if name.is_root() {
assert!(root.ends_with(&name))
}
else {
assert!(!root.ends_with(&name))
}
assert!(flat_wec.ends_with(&name));
assert!(once_wec.ends_with(&name));
assert!(twice_wec.ends_with(&name));
}
}
fn split_first_wec(mut name: ParsedDname<&'static [u8]>) {
assert_eq!(
name.to_vec().as_slice(),
b"\x03www\x07example\x03com\0"
);
assert_eq!(
name.split_first().unwrap().as_slice(),
b"\x03www".as_ref()
);
assert_eq!(
name.to_vec().as_slice(),
b"\x07example\x03com\0"
);
assert_eq!(
name.split_first().unwrap().as_slice(),
b"\x07example".as_ref()
);
assert_eq!(
name.to_vec().as_slice(),
b"\x03com\0"
);
assert_eq!(
name.split_first().unwrap().as_slice(),
b"\x03com".as_ref()
);
assert_eq!(
name.to_vec().as_slice(),
b"\0"
);
assert_eq!(name.split_first(), None);
assert_eq!(name.split_first(), None);
}
#[test]
fn split_first() {
split_first_wec(name!(flat));
split_first_wec(name!(once));
split_first_wec(name!(twice));
}
fn parent_wec(mut name: ParsedDname<&'static [u8]>) {
assert_eq!(
name.to_vec().as_slice(),
b"\x03www\x07example\x03com\0"
);
assert_eq!(name.parent(), true);
assert_eq!(
name.to_vec().as_slice(),
b"\x07example\x03com\0"
);
assert_eq!(name.parent(), true);
assert_eq!(
name.to_vec().as_slice(),
b"\x03com\0"
);
assert_eq!(name.parent(), true);
assert_eq!(
name.to_vec().as_slice(),
b"\0"
);
assert_eq!(name.parent(), false);
assert_eq!(name.parent(), false);
}
#[test]
fn parent() {
parent_wec(name!(flat));
parent_wec(name!(once));
parent_wec(name!(twice));
}
fn name_eq(parsed: ParsedDname<&[u8]>, name: ParsedDname<&[u8]>) {
assert_eq!(parsed.parser.as_slice(), name.parser.as_slice());
assert_eq!(parsed.parser.pos(), name.parser.pos());
assert_eq!(parsed.len, name.len);
assert_eq!(parsed.compressed, name.compressed);
}
fn parse(
mut parser: Parser<&[u8]>,
equals: ParsedDname<&[u8]>,
compose_len: usize
) {
let end = parser.pos() + compose_len;
name_eq(ParsedDname::parse(&mut parser).unwrap(), equals);
assert_eq!(parser.pos(), end);
}
fn skip(mut name: ParsedDname<&[u8]>, len: usize) {
let end = name.parser.pos() + len;
assert_eq!(ParsedDname::skip(&mut name.parser), Ok(()));
assert_eq!(name.parser.pos(), end);
}
fn p(slice: &'static [u8], pos: usize) -> Parser<&'static [u8]> {
let mut res = Parser::from_ref(slice);
res.advance(pos).unwrap();
res
}
#[test]
fn parse_and_skip() {
parse(name!(root).parser, name!(root), 1);
parse(name!(flat).parser, name!(flat), 17);
parse(name!(copy).parser, name!(flat), 2);
parse(name!(once).parser, name!(once), 14);
parse(name!(twice).parser, name!(twice), 6);
skip(name!(root), 1);
skip(name!(flat), 17);
skip(name!(copy), 2);
skip(name!(once), 14);
skip(name!(twice), 6);
let mut parser = p(b"\x03www\x07exam", 0);
assert_eq!(ParsedDname::parse(&mut parser.clone()),
Err(ParseError::ShortInput));
assert_eq!(ParsedDname::skip(&mut parser),
Err(ParseError::ShortInput));
let mut parser = p(b"\x03www\x07example", 0);
assert_eq!(ParsedDname::parse(&mut parser.clone()),
Err(ParseError::ShortInput));
assert_eq!(ParsedDname::skip(&mut parser),
Err(ParseError::ShortInput));
let mut parser = p(b"\x03www\xc0\xee12", 0);
assert_eq!(ParsedDname::parse(&mut parser.clone()),
Err(ParseError::ShortInput));
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
let mut parser = p(b"\x03www\x07example\xbffoo", 0);
assert!(ParsedDname::parse(&mut parser.clone()).is_err());
assert!(ParsedDname::skip(&mut parser).is_err());
let mut buf = Vec::from(&b"\x03123\0"[..]);
for _ in 0..25 {
buf.extend_from_slice(b"\x09123456789");
}
buf.extend_from_slice(b"\xc0\012");
let mut parser = Parser::from_ref(buf.as_slice());
parser.advance(5).unwrap();
let name = ParsedDname::parse(&mut parser.clone()).unwrap();
assert_eq!(name.len(), 255);
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
let mut buf = Vec::from(&b"\x041234\0"[..]);
for _ in 0..25 {
buf.extend_from_slice(b"\x09123456789");
}
buf.extend_from_slice(b"\xc0\012");
let mut parser = Parser::from_ref(buf.as_slice());
parser.advance(6).unwrap();
assert!(ParsedDname::parse(&mut parser.clone()).is_err());
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
let mut parser = p(b"\x03www\xc0\012", 0);
assert!(ParsedDname::parse(&mut parser.clone()).is_err());
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
let mut parser = p(b"\xc0\012", 0);
assert!(ParsedDname::parse(&mut parser.clone()).is_err());
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
let mut parser = p(b"\xc0\x02\xc0\012", 2);
assert!(ParsedDname::parse(&mut parser.clone()).is_err());
assert_eq!(ParsedDname::skip(&mut parser), Ok(()));
assert_eq!(parser.remaining(), 2);
}
#[test]
fn compose() {
fn step(name: ParsedDname<&[u8]>, result: &[u8]) {
let mut buf = Vec::new();
name.compose(&mut buf).unwrap();
assert_eq!(buf.as_slice(), result);
}
step(name!(root), b"\0");
step(name!(flat), WECR);
step(name!(once), WECR);
step(name!(twice), WECR);
}
#[test]
fn as_flat_slice() {
assert_eq!(name!(root).as_flat_slice(), Some(b"\0".as_ref()));
assert_eq!(name!(flat).as_flat_slice(), Some(WECR));
assert_eq!(name!(once).as_flat_slice(), None);
assert_eq!(name!(twice).as_flat_slice(), None);
}
#[test]
fn eq() {
fn step<N: ToDname + fmt::Debug>(name: N) {
assert_eq!(name!(flat), &name);
assert_eq!(name!(once), &name);
assert_eq!(name!(twice), &name);
}
fn ne_step<N: ToDname + fmt::Debug>(name: N) {
assert_ne!(name!(flat), &name);
assert_ne!(name!(once), &name);
assert_ne!(name!(twice), &name);
}
step(name!(flat));
step(name!(once));
step(name!(twice));
step(Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap());
step(Dname::from_slice(b"\x03wWw\x07EXAMPLE\x03com\0").unwrap());
step(
RelativeDname::from_octets(
b"\x03www\x07example\x03com"
).unwrap().chain_root()
);
step(
RelativeDname::from_octets(
b"\x03www\x07example"
).unwrap().chain(
Dname::from_octets(b"\x03com\0").unwrap()
).unwrap()
);
ne_step(Dname::from_slice(b"\x03ww4\x07EXAMPLE\x03com\0").unwrap());
}
}