use core::{fmt, iter};
use super::label::Label;
use super::super::octets::{Compose, OctetsBuilder, ShortBuf};
use super::relative::DnameIter;
use super::traits::{ToDname, ToEitherDname, ToLabelIter, ToRelativeDname};
use super::uncertain::UncertainDname;
#[derive(Clone, Debug)]
pub struct Chain<L, R> {
left: L,
right: R,
}
impl<L: ToEitherDname, R: ToEitherDname> Chain<L, R> {
pub(super) fn new(left: L, right: R) -> Result<Self, LongChainError> {
if left.len() + right.len() > 255 {
Err(LongChainError)
}
else {
Ok(Chain { left, right })
}
}
}
impl<Octets: AsRef<[u8]>, R: ToEitherDname> Chain<UncertainDname<Octets>, R> {
pub(super) fn new_uncertain(
left: UncertainDname<Octets>, right: R
) -> Result<Self, LongChainError> {
if let UncertainDname::Relative(ref name) = left {
if name.len() + right.len() > 255 {
return Err(LongChainError)
}
}
Ok(Chain { left, right })
}
}
impl<L: ToRelativeDname, R: ToEitherDname> Chain<L, R> {
pub fn chain<N: ToEitherDname>(
self,
other: N
) -> Result<Chain<Self, N>, LongChainError> {
Chain::new(self, other)
}
}
impl<L, R> Chain<L, R> {
pub fn unwrap(self) -> (L, R) {
(self.left, self.right)
}
}
impl<L: ToRelativeDname, R: ToEitherDname> Compose for Chain<L, R> {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
self.left.compose(target)?;
self.right.compose(target)
})
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
target.append_all(|target| {
self.left.compose_canonical(target)?;
self.right.compose_canonical(target)
})
}
}
impl<Octets, R: ToDname> Compose for Chain<UncertainDname<Octets>, R>
where Octets: AsRef<[u8]>, R: ToDname {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
match self.left {
UncertainDname::Absolute(ref name) => name.compose(target),
UncertainDname::Relative(ref name) => {
target.append_all(|target| {
name.compose(target)?;
self.right.compose(target)
})
}
}
}
fn compose_canonical<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
match self.left {
UncertainDname::Absolute(ref name) => {
name.compose_canonical(target)
}
UncertainDname::Relative(ref name) => {
target.append_all(|target| {
name.compose_canonical(target)?;
self.right.compose_canonical(target)
})
}
}
}
}
impl<'a, L: ToRelativeDname, R: ToEitherDname> ToLabelIter<'a>
for Chain<L, R> {
type LabelIter = ChainIter<'a, L, R>;
fn iter_labels(&'a self) -> Self::LabelIter {
ChainIter(self.left.iter_labels().chain(self.right.iter_labels()))
}
}
impl<'a, Octets, R> ToLabelIter<'a> for Chain<UncertainDname<Octets>, R>
where Octets: AsRef<[u8]>, R: ToDname {
type LabelIter = UncertainChainIter<'a, Octets, R>;
fn iter_labels(&'a self) -> Self::LabelIter {
match self.left {
UncertainDname::Absolute(ref name) => {
UncertainChainIter::Absolute(name.iter_labels())
}
UncertainDname::Relative(ref name) => {
UncertainChainIter::Relative(
ChainIter(name.iter_labels()
.chain(self.right.iter_labels()))
)
}
}
}
}
impl<L: ToRelativeDname, R: ToRelativeDname> ToRelativeDname for Chain<L, R> {
}
impl<L: ToRelativeDname, R: ToDname> ToDname for Chain<L, R> {
}
impl<Octets, R> ToDname for Chain<UncertainDname<Octets>, R>
where Octets: AsRef<[u8]>, R: ToDname
{ }
impl<L: fmt::Display, R: fmt::Display> fmt::Display for Chain<L, R> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.{}", self.left, self.right)
}
}
#[derive(Debug)]
pub struct ChainIter<'a, L: ToLabelIter<'a>, R: ToLabelIter<'a>>(
iter::Chain<L::LabelIter, R::LabelIter>
);
impl<'a, L, R> Clone for ChainIter<'a, L, R>
where L: ToLabelIter<'a>, R: ToLabelIter<'a> {
fn clone(&self) -> Self {
ChainIter(self.0.clone())
}
}
impl<'a, L, R> Iterator for ChainIter<'a, L, R>
where L: ToLabelIter<'a>, R: ToLabelIter<'a> {
type Item = &'a Label;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<'a, L, R> DoubleEndedIterator for ChainIter<'a, L, R>
where L: ToLabelIter<'a>, R: ToLabelIter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
pub enum UncertainChainIter<'a, Octets: AsRef<[u8]>, R: ToLabelIter<'a>> {
Absolute(DnameIter<'a>),
Relative(ChainIter<'a, UncertainDname<Octets>, R>),
}
impl<'a, Octets, R> Clone for UncertainChainIter<'a, Octets, R>
where Octets: AsRef<[u8]>, R: ToLabelIter<'a> {
fn clone(&self) -> Self {
use UncertainChainIter::*;
match *self {
Absolute(ref inner) => Absolute(inner.clone()),
Relative(ref inner) => Relative(inner.clone())
}
}
}
impl<'a, Octets, R> Iterator for UncertainChainIter<'a, Octets, R>
where Octets: AsRef<[u8]>, R: ToLabelIter<'a>
{
type Item = &'a Label;
fn next(&mut self) -> Option<Self::Item> {
match *self {
UncertainChainIter::Absolute(ref mut inner) => inner.next(),
UncertainChainIter::Relative(ref mut inner) => inner.next()
}
}
}
impl<'a, Octets, R> DoubleEndedIterator for UncertainChainIter<'a, Octets, R>
where Octets: AsRef<[u8]>, R: ToLabelIter<'a>
{
fn next_back(&mut self) -> Option<Self::Item> {
match *self {
UncertainChainIter::Absolute(ref mut inner) => inner.next_back(),
UncertainChainIter::Relative(ref mut inner) => inner.next_back()
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LongChainError;
impl fmt::Display for LongChainError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("long domain name")
}
}
#[cfg(feature = "std")]
impl std::error::Error for LongChainError { }
#[cfg(test)]
mod test {
use std::vec::Vec;
use crate::base::name::{Dname, DnameBuilder, RelativeDname, ToLabelIter};
use super::*;
#[test]
fn impls() {
fn assert_to_dname<T: ToDname>(_: &T) { }
fn assert_to_relative_dname<T: ToRelativeDname>(_: &T) { }
let rel = RelativeDname::empty_ref()
.chain(RelativeDname::empty_ref()).unwrap();
assert_to_relative_dname(&rel);
assert_to_dname(
&RelativeDname::empty_ref().chain(Dname::root_ref()).unwrap()
);
assert_to_dname(
&RelativeDname::empty_ref().chain(
RelativeDname::empty_ref()
).unwrap().chain(Dname::root_ref()).unwrap()
);
assert_to_dname(&rel.clone().chain(Dname::root_ref()).unwrap());
assert_to_relative_dname(
&rel.chain(RelativeDname::empty_ref()).unwrap()
);
assert_to_dname(
&UncertainDname::root_vec().chain(Dname::root_vec()).unwrap()
);
assert_to_dname(
&UncertainDname::empty_vec().chain(Dname::root_vec()).unwrap()
);
}
#[test]
fn name_limit() {
let mut builder = DnameBuilder::new_vec();
for _ in 0..25 {
builder.append_label(b"123456789").unwrap();
}
let left = builder.finish();
assert_eq!(left.len(), 250);
let mut builder = DnameBuilder::new_vec();
builder.append_slice(b"123").unwrap();
let five_abs = builder.clone().into_dname().unwrap();
assert_eq!(five_abs.len(), 5);
builder.push(b'4').unwrap();
let five_rel = builder.clone().finish();
assert_eq!(five_rel.len(), 5);
let six_abs = builder.clone().into_dname().unwrap();
assert_eq!(six_abs.len(), 6);
builder.push(b'5').unwrap();
let six_rel = builder.finish();
assert_eq!(six_rel.len(), 6);
assert_eq!(
left.clone().chain(five_abs.clone()).unwrap().len(),
255
);
assert_eq!(
left.clone().chain(five_rel.clone()).unwrap().len(),
255
);
assert!(left.clone().chain(six_abs.clone()).is_err());
assert!(left.clone().chain(six_rel.clone()).is_err());
assert!(
left.clone().chain(
five_rel.clone()
).unwrap().chain(five_abs.clone()).is_err()
);
assert!(
left.clone().chain(
five_rel.clone()
).unwrap().chain(five_rel.clone()).is_err()
);
let left = UncertainDname::from(left);
assert_eq!(
left.clone().chain(five_abs.clone()).unwrap().len(),
255
);
assert!(left.clone().chain(six_abs.clone()).is_err());
let left = UncertainDname::from(left.into_absolute().unwrap());
assert_eq!(
left.clone().chain(six_abs.clone()).unwrap().len(),
251
);
}
#[test]
fn iter_labels() {
fn cmp_iter<'a, I: Iterator<Item=&'a Label>>(
iter: I, labels: &[&[u8]]
) {
let labels = labels.iter().map(|s| Label::from_slice(s).unwrap());
assert!(iter.eq(labels))
}
let w = RelativeDname::from_octets(b"\x03www".as_ref()).unwrap();
let ec = RelativeDname::from_octets(
b"\x07example\x03com".as_ref()
).unwrap();
let ecr = Dname::from_octets(
b"\x07example\x03com\x00".as_ref()
).unwrap();
let fbr = Dname::from_octets(
b"\x03foo\x03bar\x00".as_ref()
).unwrap();
cmp_iter(
w.clone().chain(ec.clone()).unwrap().iter_labels(),
&[b"www", b"example", b"com"]
);
cmp_iter(
w.clone().chain(ecr.clone()).unwrap().iter_labels(),
&[b"www", b"example", b"com", b""]
);
cmp_iter(
w.clone().chain(ec.clone()).unwrap().chain(
Dname::root_ref()
).unwrap().iter_labels(),
&[b"www", b"example", b"com", b""]
);
cmp_iter(
UncertainDname::from(w.clone()).chain(
ecr.clone()
).unwrap().iter_labels(),
&[b"www", b"example", b"com", b""]
);
cmp_iter(
UncertainDname::from(ecr.clone()).chain(
fbr.clone()
).unwrap().iter_labels(),
&[b"example", b"com", b""]
);
}
#[test]
fn compose() {
let w = RelativeDname::from_octets(b"\x03www".as_ref()).unwrap();
let ec = RelativeDname::from_octets(
b"\x07example\x03com".as_ref()
).unwrap();
let ecr = Dname::from_octets(
b"\x07example\x03com\x00".as_ref()
).unwrap();
let fbr = Dname::from_octets(b"\x03foo\x03bar\x00".as_ref()).unwrap();
let mut buf = Vec::new();
w.clone().chain(ec.clone()).unwrap().compose(&mut buf).unwrap();
assert_eq!(buf, b"\x03www\x07example\x03com".as_ref());
let mut buf = Vec::new();
w.clone().chain(ecr.clone()).unwrap().compose(&mut buf).unwrap();
assert_eq!(buf, b"\x03www\x07example\x03com\x00");
let mut buf = Vec::new();
w.clone().chain(ec.clone()).unwrap().chain(
Dname::root_ref()
).unwrap().compose(&mut buf).unwrap();
assert_eq!(buf, b"\x03www\x07example\x03com\x00");
let mut buf = Vec::new();
UncertainDname::from(w.clone()).chain(
ecr.clone()
).unwrap().compose(&mut buf).unwrap();
assert_eq!(buf, b"\x03www\x07example\x03com\x00");
let mut buf = Vec::new();
UncertainDname::from(ecr.clone()).chain(
fbr.clone()
).unwrap().compose(&mut buf).unwrap();
assert_eq!(buf, b"\x07example\x03com\x00");
}
}