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

Introduce OctetsFrom and OctetsInto. #77

Merged
merged 5 commits into from
Nov 12, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ Bug Fixes
by [@vavrusa])
* Fix canonical comparison of TXT RDATA by taking the length labels into
account. ([#76] by [@vavrusa])
* Fix parsed not rejecting of malformed TXT RDATA. ([#80] by [@vavrusa])

New

* Supprt for extended errors defined in [RFC 8914]. ([#79] by [@xofyarg])

Other Changes

[#74]: https://github.com/NLnetLabs/domain/pull/74
[#75]: https://github.com/NLnetLabs/domain/pull/75
[#76]: https://github.com/NLnetLabs/domain/pull/76
[#79]: https://github.com/NLnetLabs/domain/pull/79
[#80]: https://github.com/NLnetLabs/domain/pull/80
[@vavrusa]: https://github.com/vavrusa
[@xofyarg]: https://github.com/xofyarg
[RFC 8914]: https://tools.ietf.org/html/rfc8914


## 0.5.3
Expand Down
18 changes: 16 additions & 2 deletions src/base/charstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ use core::{cmp, fmt, hash, ops, str};
};
use super::cmp::CanonicalOrd;
use super::octets::{
Compose, EmptyBuilder, FromBuilder, IntoBuilder, OctetsBuilder, OctetsRef,
Parse, ParseError, Parser, ShortBuf
Compose, EmptyBuilder, FromBuilder, IntoBuilder, OctetsBuilder, OctetsFrom,
OctetsRef, Parse, ParseError, Parser, ShortBuf
};
use super::str::{BadSymbol, Symbol, SymbolError};

Expand Down Expand Up @@ -163,6 +163,20 @@ impl CharStr<[u8]> {
}


//--- OctetsFrom

impl<Octets, SrcOctets> OctetsFrom<CharStr<SrcOctets>> for CharStr<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: CharStr<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.0).map(|octets| {
unsafe {
Self::from_octets_unchecked(octets)
}
})
}
}


//--- FromStr

impl<Octets> str::FromStr for CharStr<Octets>
Expand Down
16 changes: 15 additions & 1 deletion src/base/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::iana::{Class, Rcode, Rtype};
use super::message_builder::{AdditionalBuilder, AnswerBuilder};
use super::name::ParsedDname;
use super::octets::{
OctetsBuilder, OctetsRef, Parse, ParseError, Parser, ShortBuf
OctetsBuilder, OctetsFrom, OctetsRef, Parse, ParseError, Parser, ShortBuf
};
use super::opt::{Opt, OptRecord};
use super::question::Question;
Expand Down Expand Up @@ -597,6 +597,20 @@ impl<Octets: AsRef<[u8]>> AsRef<[u8]> for Message<Octets> {
}


//--- OctetsFrom

impl<Octets, SrcOctets> OctetsFrom<Message<SrcOctets>> for Message<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: Message<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.octets).map(|octets| {
unsafe {
Self::from_octets_unchecked(octets)
}
})
}
}


//--- IntoIterator

impl<'a, Octets> IntoIterator for &'a Message<Octets>
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 @@ -12,7 +12,7 @@ use core::str::FromStr;
use super::super::cmp::CanonicalOrd;
use super::super::octets::{
Compose, EmptyBuilder, FormError, FromBuilder, OctetsBuilder, OctetsExt,
OctetsRef, Parse, Parser, ParseError, ShortBuf
OctetsFrom, OctetsRef, Parse, Parser, ParseError, ShortBuf
};
use super::builder::{DnameBuilder, FromStrError};
use super::label::{Label, LabelTypeError, SplitLabelError};
Expand Down Expand Up @@ -588,6 +588,20 @@ impl<Octets: AsRef<T> + ?Sized, T: ?Sized> AsRef<T> for Dname<Octets> {
}


//--- OctetsFrom

impl<Octets, SrcOctets> OctetsFrom<Dname<SrcOctets>> for Dname<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: Dname<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.0).map(|octets| {
unsafe {
Self::from_octets_unchecked(octets)
}
})
}
}


//--- FromStr

impl<Octets> FromStr for Dname<Octets>
Expand Down
19 changes: 17 additions & 2 deletions src/base/name/relative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use core::cmp::Ordering;
#[cfg(feature = "std")] use std::vec::Vec;
#[cfg(feature = "bytes")] use bytes::Bytes;
use super::super::octets::{
Compose, IntoBuilder, OctetsBuilder, OctetsExt, OctetsRef, ParseError,
ShortBuf
Compose, IntoBuilder, OctetsBuilder, OctetsExt, OctetsFrom, OctetsRef,
ParseError, ShortBuf
};
use super::builder::{DnameBuilder, PushError};
use super::chain::{Chain, LongChainError};
Expand Down Expand Up @@ -569,6 +569,21 @@ impl<Octets: AsRef<T> + ?Sized, T: ?Sized> AsRef<T> for RelativeDname<Octets> {
}


//--- OctetsFrom

impl<Octets, SrcOctets>
OctetsFrom<RelativeDname<SrcOctets>> for RelativeDname<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: RelativeDname<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.0).map(|octets| {
unsafe {
Self::from_octets_unchecked(octets)
}
})
}
}


//--- ToLabelIter and ToRelativeDname

impl<'a, Octets> ToLabelIter<'a> for RelativeDname<Octets>
Expand Down
91 changes: 80 additions & 11 deletions src/base/octets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,86 @@ impl<'a, A: Array<Item = u8>> OctetsRef for &'a SmallVec<A> {
}


//------------ OctetsFrom ----------------------------------------------------

/// Convert a type from one octets type to another.
///
/// This trait allows creating a value of a type that is generic over an
/// octets sequence from an identical value using a different type of octets
/// sequence.
///
/// This is different from just `From` in that the conversion may fail if the
/// source sequence is longer than the space available for the target type.
pub trait OctetsFrom<Source>: Sized {
/// Performs the conversion.
fn octets_from(source: Source) -> Result<Self, ShortBuf>;
}


impl<'a, Source: AsRef<[u8]> + 'a> OctetsFrom<&'a Source> for &'a [u8] {
fn octets_from(source: &'a Source) -> Result<Self, ShortBuf> {
Ok(source.as_ref())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This blanket implementation is not enough. Bytes for example only supports conversion from &'static [u8]. So converting from &Record now requires cloning the record and converting each member using the owned value. Perhaps the blanket implementation could use OctetsBuilder which can convert any Source: AsRef<[u8]> into Octets?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But isn’t that rather a missing impl OctetsFrom<&'_ Record<...>> for Record<...>? Or am I misunderstanding you?

Copy link
Contributor

@vavrusa vavrusa Nov 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes you're right, I misread this, I thought it was implemented for any AsRef<[u8]>. This is not unique to Record though, any type composed of Octets that is convertible currently moves the original variable. I guess it's not going to be a big problem with Bytes as it can efficiently convert from a cloned vec, and cloning of bytes in order to be converted back to vec is cheap so it should be ok for now. impl<O> OctetsFrom<&'a Record<O, ...>> for Record<O, ...> where O: Clone would be convenient, that would make the usability similar to how Dname like types can be converted using to_dname.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It think when doing from a &Record<O> to a Record<OO>, we should go via &O: OctetsRef. So perhaps the trait bound should be where &O: OctetsRef, OO: OctetsFrom<&O> (plus lifetimes, of course). There might be a blanket impl in there somewhere, but it probably won’t work because of specialization rules.

Perhaps explore this in a different PR? Just so we get some progress here?

}
}

#[cfg(feature = "std")]
impl<Source> OctetsFrom<Source> for Vec<u8>
where Self: From<Source> {
fn octets_from(source: Source) -> Result<Self, ShortBuf> {
Ok(From::from(source))
}
}

#[cfg(feature = "bytes")]
impl<Source> OctetsFrom<Source> for Bytes
where Self: From<Source> {
fn octets_from(source: Source) -> Result<Self, ShortBuf> {
Ok(From::from(source))
}
}

#[cfg(feature = "bytes")]
impl<Source> OctetsFrom<Source> for BytesMut
where Self: From<Source> {
fn octets_from(source: Source) -> Result<Self, ShortBuf> {
Ok(From::from(source))
}
}

#[cfg(features = "smallvec")]
impl<Source, A> OctetsFrom<Source> for SmallVec<A>
where Source: AsRef<u8>, A: Array<Item = u8> {
fn octets_from(source: Source) -> Result<Self, ShortBuf> {
Ok(smallvec::ToSmallVec::to_smallvec(source.as_ref()))
}
}


//------------ OctetsInto ----------------------------------------------------

/// Convert a type from one octets type to another.
///
/// This trait allows trading in a value of a type that is generic over an
/// octets sequence for an identical value using a different type of octets
/// sequence.
///
/// This is different from just `Into` in that the conversion may fail if the
/// source sequence is longer than the space available for the target type.
///
/// This trait has a blanket implementation for all pairs of types where
/// `OctetsFrom` has been implemented.
pub trait OctetsInto<Target> {
/// Performs the conversion.
fn octets_into(self) -> Result<Target, ShortBuf>;
}

impl<Source, Target: OctetsFrom<Source>> OctetsInto<Target> for Source {
fn octets_into(self) -> Result<Target, ShortBuf> {
Target::octets_from(self)
}
}


//------------ OctetsBuilder -------------------------------------------------

/// A buffer to construct an octet sequence.
Expand Down Expand Up @@ -557,11 +637,6 @@ impl<A: Array<Item = u8>> EmptyBuilder for SmallVec<A> {
/// An octets type that can be converted into an octets builder.
pub trait IntoBuilder {
/// The type of octets builder this octets type can be converted into.
///
/// If `Builder` implements [`IntoOctets`], the `Octets` associated
/// type of that trait must be `Self`.
///
/// [`IntoOctets`]: trait.IntoOctets.html
type Builder: OctetsBuilder;

/// Converts an octets value into an octets builder.
Expand Down Expand Up @@ -620,12 +695,6 @@ impl<A: Array<Item = u8>> IntoBuilder for SmallVec<A> {
//------------ FromBuilder ---------------------------------------------------

/// An octets type that can be created from an octets builder.
///
/// This trait is a mirror of [`IntoOctets`] and only exists because otherwise
/// trait bounds become ridiculously complex. The implementations of the two
/// traits must behave identically.
///
/// [`IntoOctets`]: trait.IntoOctets.html
pub trait FromBuilder: AsRef<[u8]> + Sized {
/// The type of builder this octets type can be created from.
type Builder: OctetsBuilder<Octets = Self>;
Expand Down
29 changes: 28 additions & 1 deletion src/base/opt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ use super::iana::{OptionCode, OptRcode, Rtype};
use super::header::Header;
use super::name::ToDname;
use super::octets::{
Compose, OctetsBuilder, OctetsRef, Parse, ParseError, Parser, ShortBuf
Compose, OctetsBuilder, OctetsFrom, OctetsRef, Parse, ParseError, Parser,
ShortBuf
};
use super::rdata::RtypeRecordData;
use super::record::Record;
Expand Down Expand Up @@ -104,6 +105,16 @@ impl<Octets: AsRef<[u8]>> Opt<Octets> {
}


//--- OctetsFrom

impl<Octets, SrcOctets> OctetsFrom<Opt<SrcOctets>> for Opt<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: Opt<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.octets).map(|octets| Opt { octets })
}
}


//--- PartialEq and Eq

impl<Octets, Other> PartialEq<Opt<Other>> for Opt<Octets>
Expand Down Expand Up @@ -410,6 +421,22 @@ impl<Octets, N: ToDname> From<Record<N, Opt<Octets>>> for OptRecord<Octets> {
}


//--- OctetsFrom

impl<Octets, SrcOctets> OctetsFrom<OptRecord<SrcOctets>> for OptRecord<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(source: OptRecord<SrcOctets>) -> Result<Self, ShortBuf> {
Ok(OptRecord {
udp_payload_size: source.udp_payload_size,
ext_rcode: source.ext_rcode,
version: source.version,
flags: source.flags,
data: Opt::octets_from(source.data)?,
})
}
}


//--- Deref and AsRef

impl<Octets> ops::Deref for OptRecord<Octets> {
Expand Down
18 changes: 16 additions & 2 deletions src/base/question.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use super::cmp::CanonicalOrd;
use super::iana::{Class, Rtype};
use super::name::{ParsedDname, ToDname};
use super::octets::{
Compose, OctetsBuilder, OctetsRef, Parse, Parser, ParseError, ShortBuf
Compose, OctetsBuilder, OctetsFrom, OctetsRef, Parse, Parser, ParseError,
ShortBuf
};


Expand Down Expand Up @@ -42,7 +43,7 @@ pub struct Question<N> {

/// # Creation and Conversion
///
impl<N: ToDname> Question<N> {
impl<N> Question<N> {
/// Creates a new question from its three componets.
pub fn new(qname: N, qtype: Rtype, qclass: Class) -> Self {
Question { qname, qtype, qclass }
Expand Down Expand Up @@ -95,6 +96,19 @@ impl<N: ToDname> From<(N, Rtype)> for Question<N> {
}


//--- OctetsFrom

impl<Name, SrcName> OctetsFrom<Question<SrcName>> for Question<Name>
where Name: OctetsFrom<SrcName> {
fn octets_from(source: Question<SrcName>) -> Result<Self, ShortBuf> {
Ok(Question::new(
Name::octets_from(source.qname)?,
source.qtype, source.qclass
))
}
}


//--- PartialEq and Eq

impl<N, NN> PartialEq<Question<NN>> for Question<N>
Expand Down
19 changes: 18 additions & 1 deletion src/base/rdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use core::cmp::Ordering;
use super::cmp::CanonicalOrd;
use super::iana::Rtype;
use super::octets::{
Compose, OctetsBuilder, OctetsRef, Parse, ParseError, Parser, ShortBuf
Compose, OctetsBuilder, OctetsFrom, OctetsRef, Parse, ParseError, Parser,
ShortBuf
};


Expand Down Expand Up @@ -220,6 +221,22 @@ impl UnknownRecordData<Bytes> {
}


//--- OctetsFrom

impl<Octets, SrcOctets>
OctetsFrom<UnknownRecordData<SrcOctets>> for UnknownRecordData<Octets>
where Octets: OctetsFrom<SrcOctets> {
fn octets_from(
source: UnknownRecordData<SrcOctets>
) -> Result<Self, ShortBuf> {
Ok(UnknownRecordData {
rtype: source.rtype,
data: Octets::octets_from(source.data)?
})
}
}


//--- PartialEq and Eq

impl<Octets, Other> PartialEq<UnknownRecordData<Other>>
Expand Down
Loading