use super::super::octets::{
Compose, EmptyBuilder, FromBuilder, OctetsBuilder,
};
use super::builder::PushError;
use super::chain::{Chain, LongChainError};
use super::dname::Dname;
use super::label::Label;
use super::relative::RelativeDname;
#[cfg(feature = "bytes")]
use bytes::Bytes;
use core::cmp;
#[cfg(feature = "std")]
use std::borrow::Cow;
#[allow(clippy::len_without_is_empty)]
pub trait ToLabelIter<'a> {
type LabelIter: Iterator<Item = &'a Label> + DoubleEndedIterator + Clone;
fn iter_labels(&'a self) -> Self::LabelIter;
fn len(&'a self) -> usize {
self.iter_labels().map(Label::compose_len).sum()
}
fn starts_with<N: ToLabelIter<'a> + ?Sized>(
&'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> + ?Sized>(&'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> + ?Sized> ToLabelIter<'b> for &'a N {
type LabelIter = N::LabelIter;
fn iter_labels(&'b self) -> Self::LabelIter {
(*self).iter_labels()
}
}
pub trait ToDname: Compose + for<'a> ToLabelIter<'a> {
fn to_dname<Octets>(&self) -> Result<Dname<Octets>, PushError>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
{
let mut builder = Octets::Builder::with_capacity(self.len());
for label in self.iter_labels() {
label.build(&mut builder)?;
}
Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
#[cfg(feature = "std")]
fn to_cow(&self) -> Dname<std::borrow::Cow<[u8]>> {
let octets = self
.as_flat_slice()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
unsafe { Dname::from_octets_unchecked(octets) }
}
#[cfg(feature = "std")]
fn to_vec(&self) -> Dname<std::vec::Vec<u8>> {
self.to_dname().unwrap()
}
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> Dname<Bytes> {
self.to_dname().unwrap()
}
fn name_eq<N: ToDname + ?Sized>(&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 + ?Sized>(&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,
}
}
}
fn composed_cmp<N: ToDname + ?Sized>(&self, other: &N) -> cmp::Ordering {
if let (Some(left), Some(right)) =
(self.as_flat_slice(), other.as_flat_slice())
{
return left.cmp(right);
}
let mut self_iter = self.iter_labels();
let mut other_iter = other.iter_labels();
loop {
match (self_iter.next(), other_iter.next()) {
(Some(left), Some(right)) => match left.composed_cmp(right) {
cmp::Ordering::Equal => {}
other => return other,
},
(None, None) => return cmp::Ordering::Equal,
_ => {
unreachable!()
}
}
}
}
fn lowercase_composed_cmp<N: ToDname + ?Sized>(
&self,
other: &N,
) -> cmp::Ordering {
let mut self_iter = self.iter_labels();
let mut other_iter = other.iter_labels();
loop {
match (self_iter.next(), other_iter.next()) {
(Some(left), Some(right)) => {
match left.lowercase_composed_cmp(right) {
cmp::Ordering::Equal => {}
other => return other,
}
}
(None, None) => return cmp::Ordering::Equal,
_ => {
unreachable!()
}
}
}
}
fn rrsig_label_count(&self) -> u8 {
let mut labels = self.iter_labels();
if labels.next().unwrap().is_wildcard() {
(labels.count() - 1) as u8
} else {
labels.count() as u8
}
}
}
impl<'a, N: ToDname + ?Sized + 'a> ToDname for &'a N {}
pub trait ToRelativeDname: Compose + for<'a> ToLabelIter<'a> {
fn to_relative_dname<Octets>(
&self,
) -> Result<RelativeDname<Octets>, PushError>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder = Octets::Builder::with_capacity(self.len());
for label in self.iter_labels() {
label.build(&mut builder)?;
}
Ok(unsafe { RelativeDname::from_octets_unchecked(builder.freeze()) })
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
#[cfg(feature = "std")]
fn to_cow(&self) -> RelativeDname<std::borrow::Cow<[u8]>> {
let octets = self
.as_flat_slice()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
unsafe { RelativeDname::from_octets_unchecked(octets) }
}
#[cfg(feature = "std")]
fn to_vec(&self) -> RelativeDname<std::vec::Vec<u8>> {
self.to_relative_dname().unwrap()
}
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> RelativeDname<Bytes> {
self.to_relative_dname().unwrap()
}
fn is_empty(&self) -> bool {
self.iter_labels().next().is_none()
}
fn chain<N: ToEitherDname>(
self,
suffix: N,
) -> Result<Chain<Self, N>, LongChainError>
where
Self: Sized,
{
Chain::new(self, suffix)
}
fn chain_root(self) -> Chain<Self, Dname<&'static [u8]>>
where
Self: Sized,
{
Chain::new(self, Dname::root()).unwrap()
}
fn name_eq<N: ToRelativeDname + ?Sized>(&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 + ?Sized>(
&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 + ?Sized + 'a> ToRelativeDname for &'a N {}
pub trait ToEitherDname: Compose + for<'a> ToLabelIter<'a> {}
impl<N: Compose + for<'a> ToLabelIter<'a>> ToEitherDname for N {}