use std::cmp;
use bytes::BytesMut;
use ::bits::compose::{Compose, Compress};
use super::chain::{Chain, LongChainError};
use super::dname::Dname;
use super::label::Label;
use super::relative::RelativeDname;
pub trait ToLabelIter<'a> {
type LabelIter: Iterator<Item=&'a Label> + DoubleEndedIterator;
fn iter_labels(&'a self) -> Self::LabelIter;
fn starts_with<N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
let mut self_iter = self.iter_labels();
let mut base_iter = base.iter_labels();
loop {
match (self_iter.next(), base_iter.next()) {
(Some(sl), Some(bl)) => {
if sl != bl { return false }
}
(_, None) => return true,
(None, Some(_)) => return false,
}
}
}
fn ends_with<N: ToLabelIter<'a>>(&'a self, base: &'a N) -> bool {
let mut self_iter = self.iter_labels();
let mut base_iter = base.iter_labels();
loop {
match (self_iter.next_back(), base_iter.next_back()) {
(Some(sl), Some(bl)) => {
if sl != bl { return false }
}
(_, None) => return true,
(None, Some(_)) => return false
}
}
}
}
impl<'a, 'b, N: ToLabelIter<'b>> ToLabelIter<'b> for &'a N {
type LabelIter = N::LabelIter;
fn iter_labels(&'b self) -> Self::LabelIter {
(*self).iter_labels()
}
}
pub trait ToDname: Compose + Compress + for<'a> ToLabelIter<'a> {
fn to_name(&self) -> Dname {
let mut bytes = BytesMut::with_capacity(self.compose_len());
self.compose(&mut bytes);
unsafe {
Dname::from_bytes_unchecked(bytes.freeze())
}
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
fn name_eq<N: ToDname>(&self, other: &N) -> bool {
if let (Some(left), Some(right)) = (self.as_flat_slice(),
other.as_flat_slice()) {
left.eq_ignore_ascii_case(right)
}
else {
self.iter_labels().eq(other.iter_labels())
}
}
fn name_cmp<N: ToDname>(&self, other: &N) -> cmp::Ordering {
let mut self_iter = self.iter_labels();
let mut other_iter = other.iter_labels();
loop {
match (self_iter.next_back(), other_iter.next_back()) {
(Some(left), Some(right)) => {
match left.cmp(right) {
cmp::Ordering::Equal => {}
res => return res
}
}
(None, Some(_)) => return cmp::Ordering::Less,
(Some(_), None) => return cmp::Ordering::Greater,
(None, None) => return cmp::Ordering::Equal
}
}
}
}
impl<'a, N: ToDname + 'a> ToDname for &'a N { }
pub trait ToRelativeDname: Compose + for<'a> ToLabelIter<'a> {
fn to_name(&self) -> RelativeDname {
let mut bytes = BytesMut::with_capacity(self.compose_len());
self.compose(&mut bytes);
unsafe {
RelativeDname::from_bytes_unchecked(bytes.freeze())
}
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
fn chain<N: Compose>(
self,
suffix: N
) -> Result<Chain<Self, N>, LongChainError>
where Self: Sized {
Chain::new(self, suffix)
}
fn chain_root(self) -> Chain<Self, Dname>
where Self: Sized {
Chain::new(self, Dname::root()).unwrap()
}
fn name_eq<N: ToRelativeDname>(&self, other: &N) -> bool {
if let (Some(left), Some(right)) = (self.as_flat_slice(),
other.as_flat_slice()) {
left.eq_ignore_ascii_case(right)
}
else {
self.iter_labels().eq(other.iter_labels())
}
}
fn name_cmp<N: ToRelativeDname>(&self, other: &N) -> cmp::Ordering {
let mut self_iter = self.iter_labels();
let mut other_iter = other.iter_labels();
loop {
match (self_iter.next_back(), other_iter.next_back()) {
(Some(left), Some(right)) => {
match left.cmp(right) {
cmp::Ordering::Equal => {}
res => return res
}
}
(None, Some(_)) => return cmp::Ordering::Less,
(Some(_), None) => return cmp::Ordering::Greater,
(None, None) => return cmp::Ordering::Equal
}
}
}
}
impl<'a, N: ToRelativeDname + 'a> ToRelativeDname for &'a N { }