From 015bc0d734ef3737e2f7d8ba2c50aabe82128eb4 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Mon, 5 Feb 2024 11:35:08 +0100 Subject: [PATCH] Add OctetsFrom and Debug impls for AllOptData. (#257) This PR adds implementation for OctetsFrom and Debug to AllOptData. As a consequence, this also adds these to some of the option data types and changes Debug for some of them to be available for all octets sequences. --- Cargo.toml | 9 ++++--- src/base/opt/algsig.rs | 28 +++++++++++++++++++++- src/base/opt/chain.rs | 12 ++++++++-- src/base/opt/cookie.rs | 7 ++++++ src/base/opt/expire.rs | 7 ++++++ src/base/opt/exterr.rs | 21 +++++++++++++++- src/base/opt/keepalive.rs | 9 ++++++- src/base/opt/keytag.rs | 15 +++++++++++- src/base/opt/macros.rs | 50 ++++++++++++++++++++++++++++++++++++++- src/base/opt/mod.rs | 30 +++++++++++++++++++++-- src/base/opt/nsid.rs | 15 +++++++++++- src/base/opt/padding.rs | 15 +++++++++++- src/base/opt/subnet.rs | 7 ++++++ 13 files changed, 209 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 36acd187..01da60d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,9 @@ name = "domain" path = "src/lib.rs" [dependencies] - -octseq = { version = "0.4.0", default-features = false } +octseq = { version = "0.5", default-features = false } pin-project-lite = "0.2" -time = { version = "0.3.1", default-features = false } +time = { version = "0.3.1", default-features = false } rand = { version = "0.8", optional = true } bytes = { version = "1.0", optional = true, default-features = false } @@ -31,7 +30,7 @@ heapless = { version = "0.8", optional = true } ring = { version = "0.17", optional = true } serde = { version = "1.0.130", optional = true, features = ["derive"] } siphasher = { version = "1", optional = true } -smallvec = { version = "1", optional = true } +smallvec = { version = "1.3", optional = true } tokio = { version = "1.33", optional = true, features = ["io-util", "macros", "net", "time", "sync", "rt-multi-thread" ] } tokio-rustls = { version = "0.24", optional = true, features = [] } @@ -94,4 +93,4 @@ required-features = ["std", "rand"] [[example]] name = "client-transports" -required-features = ["net"] \ No newline at end of file +required-features = ["net"] diff --git a/src/base/opt/algsig.rs b/src/base/opt/algsig.rs index 7ba316a9..9caffde8 100644 --- a/src/base/opt/algsig.rs +++ b/src/base/opt/algsig.rs @@ -46,7 +46,7 @@ use core::marker::PhantomData; /// Once you have a value, you can iterate over the algorithms via the /// [`iter`][Understood::iter] method or use the `IntoIterator` implementation /// for a reference. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct Understood { /// A marker for the variant. marker: PhantomData, @@ -392,6 +392,32 @@ where } } +//--- Debug + +impl + ?Sized> fmt::Debug for Understood { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Understood") + .field(&format_args!("{}", self)) + .finish() + } +} + +impl + ?Sized> fmt::Debug for Understood { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Understood") + .field(&format_args!("{}", self)) + .finish() + } +} + +impl + ?Sized> fmt::Debug for Understood { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Understood") + .field(&format_args!("{}", self)) + .finish() + } +} + //--- Extended Opt and OptBuilder impl Opt { diff --git a/src/base/opt/chain.rs b/src/base/opt/chain.rs index 4ab9f452..011977f1 100644 --- a/src/base/opt/chain.rs +++ b/src/base/opt/chain.rs @@ -29,7 +29,7 @@ use core::cmp::Ordering; /// point of the included records, i.e., the suffix of the queried name /// furthest away from the root to which the requesting resolver already has /// all necessary records. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct Chain { /// The start name AKA ‘closest trust point.’ start: Name @@ -163,7 +163,7 @@ impl ComposeOptData for Chain { } } -//--- Display +//--- Display and Debug impl fmt::Display for Chain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -171,6 +171,14 @@ impl fmt::Display for Chain { } } +impl fmt::Debug for Chain { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Chain") + .field("start", &format_args!("{}", self.start)) + .finish() + } +} + //--- Extended Opt and OptBuilder impl Opt { diff --git a/src/base/opt/cookie.rs b/src/base/opt/cookie.rs index 320b333c..d6d63d26 100644 --- a/src/base/opt/cookie.rs +++ b/src/base/opt/cookie.rs @@ -156,6 +156,13 @@ impl Cookie { ) ) } + + /// Placeholder for unnecessary octets conversion. + /// + /// This method only exists for the `AllOptData` macro. + pub(super) fn try_octets_from(src: Self) -> Result { + Ok(src) + } } diff --git a/src/base/opt/expire.rs b/src/base/opt/expire.rs index ec38739a..8055b3b1 100644 --- a/src/base/opt/expire.rs +++ b/src/base/opt/expire.rs @@ -55,6 +55,13 @@ impl Expire { u32::parse(parser).map(|res| Expire::new(Some(res))) } } + + /// Placeholder for unnecessary octets conversion. + /// + /// This method only exists for the `AllOptData` macro. + pub(super) fn try_octets_from(src: Self) -> Result { + Ok(src) + } } //--- OptData diff --git a/src/base/opt/exterr.rs b/src/base/opt/exterr.rs index 77ef10b1..a6e46b38 100644 --- a/src/base/opt/exterr.rs +++ b/src/base/opt/exterr.rs @@ -14,7 +14,7 @@ use super::{ BuildDataError, LongOptData, Opt, OptData, ComposeOptData, ParseOptData }; use octseq::builder::OctetsBuilder; -use octseq::octets::Octets; +use octseq::octets::{Octets, OctetsFrom}; use octseq::parse::Parser; use octseq::str::Str; use core::{fmt, hash, str}; @@ -146,6 +146,25 @@ where Octs: AsRef<[u8]> { } } +//--- OctetsFrom + +impl OctetsFrom> for ExtendedError +where + Octs: OctetsFrom +{ + type Error = Octs::Error; + + fn try_octets_from( + source: ExtendedError + ) -> Result { + let text = match source.text { + Some(Ok(text)) => Some(Ok(Str::try_octets_from(text)?)), + Some(Err(octs)) => Some(Err(Octs::try_octets_from(octs)?)), + None => None, + }; + Ok(Self { code: source.code, text }) + } +} //--- OptData, ParseOptData, and ComposeOptData impl OptData for ExtendedError { diff --git a/src/base/opt/keepalive.rs b/src/base/opt/keepalive.rs index bf7cc7c3..c827f7a7 100644 --- a/src/base/opt/keepalive.rs +++ b/src/base/opt/keepalive.rs @@ -55,6 +55,13 @@ impl TcpKeepalive { IdleTimeout::parse(parser).map(|v| Self::new(Some(v))) } } + + /// Placeholder for unnecessary octets conversion. + /// + /// This method only exists for the `AllOptData` macro. + pub(super) fn try_octets_from(src: Self) -> Result { + Ok(src) + } } //--- OptData @@ -144,7 +151,7 @@ impl IdleTimeout { const COMPOSE_LEN: u16 = 2; /// Parses a value from its wire format. - fn parse>( + fn parse + ?Sized>( parser: &mut Parser ) -> Result { u16::parse(parser).map(Self) diff --git a/src/base/opt/keytag.rs b/src/base/opt/keytag.rs index 8bb35d87..ba769342 100644 --- a/src/base/opt/keytag.rs +++ b/src/base/opt/keytag.rs @@ -13,7 +13,7 @@ use super::super::message_builder::OptBuilder; use super::super::wire::{Composer, ParseError}; use super::{Opt, OptData, ComposeOptData, ParseOptData}; use octseq::builder::OctetsBuilder; -use octseq::octets::Octets; +use octseq::octets::{Octets, OctetsFrom}; use octseq::parse::Parser; use core::{borrow, fmt, hash}; use core::cmp::Ordering; @@ -149,6 +149,19 @@ impl KeyTag { } } +//--- OctetsFrom + +impl OctetsFrom> for KeyTag +where Octs: OctetsFrom { + type Error = Octs::Error; + + fn try_octets_from(src: KeyTag) -> Result { + Octs::try_octets_from(src.octets).map(|octets| unsafe { + Self::from_octets_unchecked(octets) + }) + } +} + //--- AsRef, AsMut, Borrow, BorrowMut impl + ?Sized> AsRef<[u8]> for KeyTag { diff --git a/src/base/opt/macros.rs b/src/base/opt/macros.rs index 373f9707..7bc3a40d 100644 --- a/src/base/opt/macros.rs +++ b/src/base/opt/macros.rs @@ -16,7 +16,6 @@ macro_rules! opt_types { //------------ AllOptData -------------------------------------------- - // TODO Impl Debug. #[derive(Clone)] #[non_exhaustive] pub enum AllOptData { @@ -26,6 +25,37 @@ macro_rules! opt_types { Other(UnknownOptData), } + //--- OctetsFrom + + impl + OctetsFrom> + for AllOptData + where + Octs: OctetsFrom, + Name: OctetsFrom, + { + type Error = Octs::Error; + + fn try_octets_from( + source: AllOptData, + ) -> Result { + match source { + $( $( + AllOptData::$opt(opt) => { + Ok(AllOptData::$opt( + $module::$opt::try_octets_from(opt)? + )) + }, + )* )* + AllOptData::Other(opt) => { + Ok(AllOptData::Other( + UnknownOptData::try_octets_from(opt)? + )) + } + } + } + } + //--- From $( $( @@ -101,5 +131,23 @@ macro_rules! opt_types { } } } + + //--- Debug + + impl fmt::Debug for AllOptData + where Octs: AsRef<[u8]>, Name: fmt::Display { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + $( $( + AllOptData::$opt(ref inner) => { + fmt::Debug::fmt(inner, f) + } + )* )* + AllOptData::Other(ref inner) => { + fmt::Debug::fmt(inner, f) + } + } + } + } } } diff --git a/src/base/opt/mod.rs b/src/base/opt/mod.rs index 5557ce94..27fcbab1 100644 --- a/src/base/opt/mod.rs +++ b/src/base/opt/mod.rs @@ -830,7 +830,7 @@ pub trait ComposeOptData: OptData { /// An OPT option in its raw form. /// /// This type accepts any option type via its option code and raw data. -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct UnknownOptData { /// The option code for the option. code: OptionCode, @@ -888,6 +888,23 @@ impl UnknownOptData { } } +//--- OctetsFrom + +impl OctetsFrom> + for UnknownOptData +where + Octs: OctetsFrom, +{ + type Error = Octs::Error; + + fn try_octets_from( + src: UnknownOptData, + ) -> Result { + Ok(unsafe { + Self::new_unchecked(src.code, Octs::try_octets_from(src.data)?) + }) + } +} //--- AsRef and AsMut impl AsRef for UnknownOptData { @@ -947,7 +964,7 @@ impl> ComposeOptData for UnknownOptData { } } -//--- Display +//--- Display and Debug impl> fmt::Display for UnknownOptData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -955,6 +972,15 @@ impl> fmt::Display for UnknownOptData { } } +impl> fmt::Debug for UnknownOptData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("UnknownOptData") + .field("code", &self.code) + .field("data", &format_args!("{}", self)) + .finish() + } +} + //============ Error Types =================================================== //------------ LongOptData --------------------------------------------------- diff --git a/src/base/opt/nsid.rs b/src/base/opt/nsid.rs index 45207270..50399c31 100644 --- a/src/base/opt/nsid.rs +++ b/src/base/opt/nsid.rs @@ -14,7 +14,7 @@ use super::{ BuildDataError, LongOptData, Opt, OptData, ComposeOptData, ParseOptData }; use octseq::builder::OctetsBuilder; -use octseq::octets::Octets; +use octseq::octets::{Octets, OctetsFrom}; use octseq::parse::Parser; use core::{borrow, fmt, hash, str}; use core::cmp::Ordering; @@ -129,6 +129,19 @@ impl Nsid { } } +//--- OctetsFrom + +impl OctetsFrom> for Nsid +where Octs: OctetsFrom { + type Error = Octs::Error; + + fn try_octets_from(src: Nsid) -> Result { + Octs::try_octets_from(src.octets).map(|octets| unsafe { + Self::from_octets_unchecked(octets) + }) + } +} + //--- AsRef and Borrow impl + ?Sized> AsRef<[u8]> for Nsid { diff --git a/src/base/opt/padding.rs b/src/base/opt/padding.rs index 086a70ad..33b7446d 100644 --- a/src/base/opt/padding.rs +++ b/src/base/opt/padding.rs @@ -14,7 +14,7 @@ use super::super::message_builder::OptBuilder; use super::super::wire::{Compose, Composer, ParseError}; use super::{LongOptData, OptData, ComposeOptData, ParseOptData}; use octseq::builder::OctetsBuilder; -use octseq::octets::Octets; +use octseq::octets::{Octets, OctetsFrom}; use octseq::parse::Parser; @@ -91,6 +91,19 @@ impl Padding { } } +//--- OctetsFrom + +impl OctetsFrom> for Padding +where Octs: OctetsFrom { + type Error = Octs::Error; + + fn try_octets_from(src: Padding) -> Result { + Octs::try_octets_from(src.octets).map(|octets| unsafe { + Self::from_octets_unchecked(octets) + }) + } +} + //--- AsRef and Borrow impl + ?Sized> AsRef<[u8]> for Padding { diff --git a/src/base/opt/subnet.rs b/src/base/opt/subnet.rs index 7a6f3efc..eae4f9ac 100644 --- a/src/base/opt/subnet.rs +++ b/src/base/opt/subnet.rs @@ -169,6 +169,13 @@ impl ClientSubnet { addr, }) } + + /// Placeholder for unnecessary octets conversion. + /// + /// This method only exists for the `AllOptData` macro. + pub(super) fn try_octets_from(src: Self) -> Result { + Ok(src) + } } //--- OptData