use super::absolute::Name;
use super::chain::{Chain, LongChainError};
use super::label::Label;
use super::relative::RelativeName;
#[cfg(feature = "bytes")]
use bytes::Bytes;
use core::convert::Infallible;
use core::{cmp, fmt};
use octseq::builder::{
infallible, BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
OctetsBuilder, ShortBuf,
};
#[cfg(feature = "std")]
use std::borrow::Cow;
pub trait ToLabelIter {
type LabelIter<'a>: Iterator<Item = &'a Label>
+ DoubleEndedIterator
+ Clone
where
Self: 'a;
fn iter_labels(&self) -> Self::LabelIter<'_>;
fn compose_len(&self) -> u16 {
self.iter_labels().map(|label| label.compose_len()).sum()
}
fn starts_with<N: ToLabelIter + ?Sized>(&self, base: &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 + ?Sized>(&self, base: &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<'r, N: ToLabelIter + ?Sized> ToLabelIter for &'r N {
type LabelIter<'a>
= N::LabelIter<'a>
where
'r: 'a,
N: 'a;
fn iter_labels(&self) -> Self::LabelIter<'_> {
(*self).iter_labels()
}
}
pub trait ToName: ToLabelIter {
fn try_to_name<Octets>(
&self,
) -> Result<Name<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
self.iter_labels()
.try_for_each(|label| label.compose(&mut builder))?;
Ok(unsafe { Name::from_octets_unchecked(builder.freeze()) })
}
fn to_name<Octets>(&self) -> Name<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<AppendError = Infallible>,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
infallible(self.try_to_name())
}
fn try_to_canonical_name<Octets>(
&self,
) -> Result<Name<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
self.iter_labels()
.try_for_each(|label| label.compose_canonical(&mut builder))?;
Ok(unsafe { Name::from_octets_unchecked(builder.freeze()) })
}
fn to_canonical_name<Octets>(&self) -> Name<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<AppendError = Infallible>,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
infallible(self.try_to_canonical_name())
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
fn compose<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
if let Some(slice) = self.as_flat_slice() {
target.append_slice(slice)
} else {
for label in self.iter_labels() {
label.compose(target)?;
}
Ok(())
}
}
fn compose_canonical<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
for label in self.iter_labels() {
label.compose_canonical(target)?;
}
Ok(())
}
#[cfg(feature = "std")]
fn to_cow(&self) -> Name<std::borrow::Cow<'_, [u8]>> {
let octets = self
.as_flat_slice()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
unsafe { Name::from_octets_unchecked(octets) }
}
#[cfg(feature = "std")]
fn to_vec(&self) -> Name<std::vec::Vec<u8>> {
self.to_name()
}
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> Name<Bytes> {
self.to_name()
}
fn name_eq<N: ToName + ?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: ToName + ?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: ToName + ?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: ToName + ?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
}
}
fn fmt_with_dot(&self) -> DisplayWithDot<'_, Self> {
DisplayWithDot(self)
}
}
pub struct DisplayWithDot<'a, T: ?Sized>(&'a T);
impl<T> fmt::Display for DisplayWithDot<'_, T>
where
T: ToLabelIter + ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut labels = self.0.iter_labels();
let first = match labels.next() {
Some(first) => first,
None => unreachable!("at least 1 label must be present"),
};
if first.is_root() {
f.write_str(".")
} else {
write!(f, "{}", first)?;
for label in labels {
write!(f, ".{}", label)?
}
Ok(())
}
}
}
impl<'a, N: ToName + ?Sized + 'a> ToName for &'a N {}
pub trait ToRelativeName: ToLabelIter {
fn try_to_relative_name<Octets>(
&self,
) -> Result<RelativeName<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
self.iter_labels()
.try_for_each(|label| label.compose(&mut builder))?;
Ok(unsafe { RelativeName::from_octets_unchecked(builder.freeze()) })
}
fn to_relative_name<Octets>(&self) -> RelativeName<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<AppendError = Infallible>,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
infallible(self.try_to_relative_name())
}
fn try_to_canonical_relative_name<Octets>(
&self,
) -> Result<RelativeName<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
self.iter_labels()
.try_for_each(|label| label.compose_canonical(&mut builder))?;
Ok(unsafe { RelativeName::from_octets_unchecked(builder.freeze()) })
}
fn to_canonical_relative_name<Octets>(&self) -> RelativeName<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<AppendError = Infallible>,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
infallible(self.try_to_canonical_relative_name())
}
fn as_flat_slice(&self) -> Option<&[u8]> {
None
}
fn compose<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
if let Some(slice) = self.as_flat_slice() {
target.append_slice(slice)
} else {
for label in self.iter_labels() {
label.compose(target)?;
}
Ok(())
}
}
fn compose_canonical<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
for label in self.iter_labels() {
label.compose_canonical(target)?;
}
Ok(())
}
#[cfg(feature = "std")]
fn to_cow(&self) -> RelativeName<std::borrow::Cow<'_, [u8]>> {
let octets = self
.as_flat_slice()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
unsafe { RelativeName::from_octets_unchecked(octets) }
}
#[cfg(feature = "std")]
fn to_vec(&self) -> RelativeName<std::vec::Vec<u8>> {
self.to_relative_name()
}
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> RelativeName<Bytes> {
self.to_relative_name()
}
fn is_empty(&self) -> bool {
self.iter_labels().next().is_none()
}
fn chain<N: ToLabelIter>(
self,
suffix: N,
) -> Result<Chain<Self, N>, LongChainError>
where
Self: Sized,
{
Chain::new(self, suffix)
}
fn chain_root(self) -> Chain<Self, Name<&'static [u8]>>
where
Self: Sized,
{
Chain::new(self, Name::root()).unwrap()
}
fn name_eq<N: ToRelativeName + ?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: ToRelativeName + ?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: ToRelativeName + ?Sized + 'a> ToRelativeName for &'a N {}
pub trait FlattenInto<Target>: Sized {
type AppendError: Into<ShortBuf>;
fn try_flatten_into(self) -> Result<Target, Self::AppendError>;
fn flatten_into(self) -> Target
where
Self::AppendError: Into<Infallible>,
{
infallible(self.try_flatten_into())
}
}