Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move flatten_into for flattening domain names into a trait. #216

Merged
merged 6 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ name = "domain"
path = "src/lib.rs"

[dependencies]
octseq = "0.2"
octseq = { git = "https://github.com/NLnetLabs/octseq.git" }
time = "0.3.1"

rand = { version = "0.8", optional = true }
Expand Down
29 changes: 28 additions & 1 deletion src/base/name/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
use super::super::scan::Scanner;
use super::label::Label;
use super::relative::DnameIter;
use super::traits::{ToDname, ToLabelIter, ToRelativeDname};
use super::traits::{FlattenInto, ToDname, ToLabelIter, ToRelativeDname};
use super::uncertain::UncertainDname;
use super::Dname;
use core::{fmt, iter};
use octseq::builder::{
BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
};

//------------ Chain ---------------------------------------------------------

Expand Down Expand Up @@ -171,6 +174,30 @@ where
{
}

//--- FlattenInto

impl<L, R, Target> FlattenInto<Dname<Target>> for Chain<L, R>
where
L: ToRelativeDname,
R: ToDname,
R: FlattenInto<Dname<Target>, AppendError = BuilderAppendError<Target>>,
Target: FromBuilder,
<Target as FromBuilder>::Builder: EmptyBuilder,
{
type AppendError = BuilderAppendError<Target>;

fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
if self.left.is_empty() {
self.right.try_flatten_into()
} else {
let mut builder =
Target::Builder::with_capacity(self.compose_len().into());
self.compose(&mut builder)?;
Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
}
}
}

//--- Display

impl<L: fmt::Display, R: fmt::Display> fmt::Display for Chain<L, R> {
Expand Down
16 changes: 15 additions & 1 deletion src/base/name/dname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::super::wire::{FormError, ParseError};
use super::builder::{DnameBuilder, FromStrError};
use super::label::{Label, LabelTypeError, SplitLabelError};
use super::relative::{DnameIter, RelativeDname};
use super::traits::{ToDname, ToLabelIter};
use super::traits::{FlattenInto, ToDname, ToLabelIter};
#[cfg(feature = "bytes")]
use bytes::Bytes;
use core::ops::{Bound, RangeBounds};
Expand Down Expand Up @@ -748,6 +748,20 @@ where
}
}

//--- FlattenInto

impl<Octs, Target> FlattenInto<Dname<Target>> for Dname<Octs>
where
Target: OctetsFrom<Octs>,
{
type AppendError = Target::Error;

fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
Target::try_octets_from(self.0)
.map(|octets| unsafe { Dname::from_octets_unchecked(octets) })
}
}

//--- PartialEq, and Eq

impl<Octs, N> PartialEq<N> for Dname<Octs>
Expand Down
2 changes: 1 addition & 1 deletion src/base/name/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub use self::relative::{
DnameIter, RelativeDname, RelativeDnameError, RelativeFromStrError,
StripSuffixError,
};
pub use self::traits::{ToDname, ToLabelIter, ToRelativeDname};
pub use self::traits::{FlattenInto, ToDname, ToLabelIter, ToRelativeDname};
pub use self::uncertain::UncertainDname;

mod builder;
Expand Down
55 changes: 29 additions & 26 deletions src/base/name/parsed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ use super::super::wire::{FormError, ParseError};
use super::dname::Dname;
use super::label::{Label, LabelTypeError};
use super::relative::RelativeDname;
use super::traits::{ToDname, ToLabelIter};
use super::PushError;
use super::traits::{FlattenInto, ToDname, ToLabelIter};
use core::{cmp, fmt, hash};
use octseq::builder::{EmptyBuilder, FromBuilder};
use octseq::octets::{Octets, OctetsFrom};
use octseq::builder::{
BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
OctetsBuilder,
};
use octseq::octets::Octets;
use octseq::parse::Parser;

//------------ ParsedDname ---------------------------------------------------
Expand Down Expand Up @@ -225,28 +227,6 @@ impl<Octs: AsRef<[u8]>> ParsedDname<Octs> {
}
}

impl<Octs: Octets> ParsedDname<Octs> {
/// Flatten `ParsedDname` into a `Dname` in case it is compressed,
/// otherwise cheap copy the underlying octets.
pub fn flatten_into<Target>(self) -> Result<Dname<Target>, PushError>
where
Target: for<'a> OctetsFrom<Octs::Range<'a>> + FromBuilder,
<Target as FromBuilder>::Builder: EmptyBuilder,
{
if self.is_compressed() {
self.to_dname()
} else {
let range = self
.parser()
.parse_octets(self.name_len.into())
.map_err(|_| PushError::ShortBuf)?;
let octets = Target::try_octets_from(range)
.map_err(|_| PushError::ShortBuf)?;
Ok(unsafe { Dname::from_octets_unchecked(octets) })
}
}
}

impl<Octs> ParsedDname<Octs> {
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
Expand Down Expand Up @@ -401,6 +381,29 @@ impl<Octs: AsRef<[u8]>> From<Dname<Octs>> for ParsedDname<Octs> {
}
}

//--- FlattenInto

impl<Octs, Target> FlattenInto<Dname<Target>> for ParsedDname<Octs>
where
Octs: Octets,
Target: FromBuilder,
<Target as FromBuilder>::Builder: EmptyBuilder,
{
type AppendError = BuilderAppendError<Target>;

fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
let mut builder =
Target::Builder::with_capacity(self.compose_len().into());
if let Some(slice) = self.as_flat_slice() {
builder.append_slice(slice)?;
} else {
self.iter_labels()
.try_for_each(|label| label.compose(&mut builder))?;
}
Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
}
}

//--- PartialEq and Eq

impl<Octs, N> PartialEq<N> for ParsedDname<Octs>
Expand Down
68 changes: 38 additions & 30 deletions src/base/name/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
//!
//! This is a private module. Its public traits are re-exported by the parent.

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;
use core::convert::Infallible;
use octseq::builder::{
EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder,
infallible, BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
OctetsBuilder, ShortBuf,
};
#[cfg(feature = "std")]
use std::borrow::Cow;
Expand Down Expand Up @@ -116,34 +117,32 @@ pub trait ToDname: ToLabelIter {
/// some types of names.
///
/// [`Dname`]: struct.Dname.html
fn to_dname<Octets>(&self) -> Result<Dname<Octets>, PushError>
fn to_dname<Octets>(
&self,
) -> Result<Dname<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
for label in self.iter_labels() {
label
.compose(&mut builder)
.map_err(|_| PushError::ShortBuf)?;
}
self.iter_labels()
.try_for_each(|label| label.compose(&mut builder))?;
Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
}

/// Converts the name into a single name in canonical form.
fn to_canonical_dname<Octets>(&self) -> Result<Dname<Octets>, PushError>
fn to_canonical_dname<Octets>(
&self,
) -> Result<Dname<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
for label in self.iter_labels() {
label
.compose_canonical(&mut builder)
.map_err(|_| PushError::ShortBuf)?;
}
self.iter_labels()
.try_for_each(|label| label.compose_canonical(&mut builder))?;
Ok(unsafe { Dname::from_octets_unchecked(builder.freeze()) })
}

Expand Down Expand Up @@ -203,13 +202,13 @@ pub trait ToDname: ToLabelIter {
/// Returns the domain name assembled into a `Vec<u8>`.
#[cfg(feature = "std")]
fn to_vec(&self) -> Dname<std::vec::Vec<u8>> {
self.to_dname().unwrap()
infallible(self.to_dname())
}

/// Returns the domain name assembled into a bytes value.
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> Dname<Bytes> {
self.to_dname().unwrap()
infallible(self.to_dname())
}

/// Tests whether `self` and `other` are equal.
Expand Down Expand Up @@ -356,36 +355,30 @@ pub trait ToRelativeDname: ToLabelIter {
/// [`RelativeDname`]: struct.RelativeDname.html
fn to_relative_dname<Octets>(
&self,
) -> Result<RelativeDname<Octets>, PushError>
) -> Result<RelativeDname<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
for label in self.iter_labels() {
label
.compose(&mut builder)
.map_err(|_| PushError::ShortBuf)?;
}
self.iter_labels()
.try_for_each(|label| label.compose(&mut builder))?;
Ok(unsafe { RelativeDname::from_octets_unchecked(builder.freeze()) })
}

/// Converts the name into a single name in canonical form.
fn to_canonical_relative_dname<Octets>(
&self,
) -> Result<RelativeDname<Octets>, PushError>
) -> Result<RelativeDname<Octets>, BuilderAppendError<Octets>>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder: EmptyBuilder,
{
let mut builder =
Octets::Builder::with_capacity(self.compose_len().into());
for label in self.iter_labels() {
label
.compose_canonical(&mut builder)
.map_err(|_| PushError::ShortBuf)?;
}
self.iter_labels()
.try_for_each(|label| label.compose_canonical(&mut builder))?;
Ok(unsafe { RelativeDname::from_octets_unchecked(builder.freeze()) })
}

Expand Down Expand Up @@ -441,13 +434,13 @@ pub trait ToRelativeDname: ToLabelIter {
/// Returns the domain name assembled into a `Vec<u8>`.
#[cfg(feature = "std")]
fn to_vec(&self) -> RelativeDname<std::vec::Vec<u8>> {
self.to_relative_dname().unwrap()
infallible(self.to_relative_dname())
}

/// Returns the domain name assembled into a bytes value.
#[cfg(feature = "bytes")]
fn to_bytes(&self) -> RelativeDname<Bytes> {
self.to_relative_dname().unwrap()
infallible(self.to_relative_dname())
}

/// Returns whether the name is empty.
Expand Down Expand Up @@ -527,3 +520,18 @@ pub trait ToRelativeDname: ToLabelIter {
}

impl<'a, N: ToRelativeDname + ?Sized + 'a> ToRelativeDname for &'a N {}

//------------ FlattenInto ---------------------------------------------------

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())
}
}
26 changes: 23 additions & 3 deletions src/base/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use super::cmp::CanonicalOrd;
use super::iana::{Class, Rtype};
use super::name::{ParsedDname, ToDname};
use super::name::{FlattenInto, ParsedDname, ToDname};
use super::rdata::{ComposeRecordData, ParseRecordData, RecordData};
use super::wire::{Compose, Composer, FormError, Parse, ParseError};
use core::cmp::Ordering;
Expand Down Expand Up @@ -242,7 +242,7 @@ impl<N, D> From<(N, u32, D)> for Record<N, D> {
}
}

//--- OctetsFrom
//--- OctetsFrom and FlattenInto
//
// XXX We don’t have blanket FromOctets for a type T into itself, so this may
// not always work as expected. Not sure what we can do about it?
Expand All @@ -268,6 +268,26 @@ where
}
}

impl<Name, TName, Data, TData> FlattenInto<Record<TName, TData>>
for Record<Name, Data>
where
Name: FlattenInto<TName>,
Data: FlattenInto<TData, AppendError = Name::AppendError>,
{
type AppendError = Name::AppendError;

fn try_flatten_into(
self,
) -> Result<Record<TName, TData>, Name::AppendError> {
Ok(Record::new(
self.owner.try_flatten_into()?,
self.class,
self.ttl,
self.data.try_flatten_into()?,
))
}
}

//--- PartialEq and Eq

impl<N, NN, D, DD> PartialEq<Record<NN, DD>> for Record<N, D>
Expand Down Expand Up @@ -1494,7 +1514,7 @@ mod test {
#[cfg(feature = "bytes")]
fn ds_octets_into() {
use super::*;
use crate::base::iana::{DigestAlg, SecAlg};
use crate::base::iana::{Class, DigestAlg, SecAlg};
use crate::base::name::Dname;
use crate::rdata::Ds;
use bytes::Bytes;
Expand Down
4 changes: 2 additions & 2 deletions src/rdata/aaaa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ impl Aaaa {
self.addr = addr
}

pub(super) fn flatten_into<E>(self) -> Result<Aaaa, E> {
pub(super) fn convert_octets<E>(self) -> Result<Self, E> {
Ok(self)
}

pub(super) fn convert_octets<E>(self) -> Result<Self, E> {
pub(super) fn flatten<E>(self) -> Result<Self, E> {
Ok(self)
}

Expand Down
Loading