use super::rfc4034::RtypeBitmap;
use crate::base::cmp::CanonicalOrd;
use crate::base::iana::{Nsec3HashAlg, Rtype};
use crate::base::name::PushError;
use crate::base::octets::{
Compose, EmptyBuilder, FromBuilder, OctetsBuilder, OctetsFrom,
OctetsInto, OctetsRef, Parse, ParseError, Parser, ShortBuf,
};
#[cfg(feature = "serde")]
use crate::base::octets::{DeserializeOctets, SerializeOctets};
use crate::base::rdata::RtypeRecordData;
#[cfg(feature = "master")]
use crate::master::scan::{CharSource, Scan, ScanError, Scanner};
use crate::utils::{base16, base32};
#[cfg(feature = "bytes")]
use bytes::Bytes;
use core::cmp::Ordering;
use core::{fmt, hash, ops, str};
#[derive(Clone)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(bound(
serialize = "
Octets: crate::base::octets::SerializeOctets + AsRef<[u8]>,
",
deserialize = "
Octets: FromBuilder + crate::base::octets::DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder
+ AsRef<[u8]> + AsMut<[u8]>,
",
))
)]
pub struct Nsec3<Octets> {
hash_algorithm: Nsec3HashAlg,
flags: u8,
iterations: u16,
salt: Nsec3Salt<Octets>,
next_owner: OwnerHash<Octets>,
types: RtypeBitmap<Octets>,
}
impl<Octets> Nsec3<Octets> {
pub fn new(
hash_algorithm: Nsec3HashAlg,
flags: u8,
iterations: u16,
salt: Nsec3Salt<Octets>,
next_owner: OwnerHash<Octets>,
types: RtypeBitmap<Octets>,
) -> Self {
Nsec3 {
hash_algorithm,
flags,
iterations,
salt,
next_owner,
types,
}
}
pub fn hash_algorithm(&self) -> Nsec3HashAlg {
self.hash_algorithm
}
pub fn flags(&self) -> u8 {
self.flags
}
pub fn opt_out(&self) -> bool {
self.flags & 0x01 != 0
}
pub fn iterations(&self) -> u16 {
self.iterations
}
pub fn salt(&self) -> &Nsec3Salt<Octets> {
&self.salt
}
pub fn next_owner(&self) -> &OwnerHash<Octets> {
&self.next_owner
}
pub fn types(&self) -> &RtypeBitmap<Octets> {
&self.types
}
}
impl<SrcOctets> Nsec3<SrcOctets> {
pub fn flatten_into<Octets>(self) -> Result<Nsec3<Octets>, PushError>
where
Octets: OctetsFrom<SrcOctets>,
{
let Self {
hash_algorithm,
flags,
iterations,
salt,
next_owner,
types,
} = self;
Ok(Nsec3::new(
hash_algorithm,
flags,
iterations,
salt.octets_into()?,
next_owner.octets_into()?,
types.octets_into()?,
))
}
}
impl<Octets, SrcOctets> OctetsFrom<Nsec3<SrcOctets>> for Nsec3<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(source: Nsec3<SrcOctets>) -> Result<Self, ShortBuf> {
Ok(Nsec3::new(
source.hash_algorithm,
source.flags,
source.iterations,
Nsec3Salt::octets_from(source.salt)?,
OwnerHash::octets_from(source.next_owner)?,
RtypeBitmap::octets_from(source.types)?,
))
}
}
impl<Octets, Other> PartialEq<Nsec3<Other>> for Nsec3<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn eq(&self, other: &Nsec3<Other>) -> bool {
self.hash_algorithm == other.hash_algorithm
&& self.flags == other.flags
&& self.iterations == other.iterations
&& self.salt == other.salt
&& self.next_owner == other.next_owner
&& self.types == other.types
}
}
impl<Octets: AsRef<[u8]>> Eq for Nsec3<Octets> {}
impl<Octets, Other> PartialOrd<Nsec3<Other>> for Nsec3<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn partial_cmp(&self, other: &Nsec3<Other>) -> Option<Ordering> {
match self.hash_algorithm.partial_cmp(&other.hash_algorithm) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.flags.partial_cmp(&other.flags) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.iterations.partial_cmp(&other.iterations) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.salt.partial_cmp(&other.salt) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.next_owner.partial_cmp(&other.next_owner) {
Some(Ordering::Equal) => {}
other => return other,
}
self.types.partial_cmp(&other.types)
}
}
impl<Octets, Other> CanonicalOrd<Nsec3<Other>> for Nsec3<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn canonical_cmp(&self, other: &Nsec3<Other>) -> Ordering {
match self.hash_algorithm.cmp(&other.hash_algorithm) {
Ordering::Equal => {}
other => return other,
}
match self.flags.cmp(&other.flags) {
Ordering::Equal => {}
other => return other,
}
match self.iterations.cmp(&other.iterations) {
Ordering::Equal => {}
other => return other,
}
match self.salt.canonical_cmp(&other.salt) {
Ordering::Equal => {}
other => return other,
}
match self.next_owner.canonical_cmp(&other.next_owner) {
Ordering::Equal => {}
other => return other,
}
self.types.canonical_cmp(&other.types)
}
}
impl<Octets: AsRef<[u8]>> Ord for Nsec3<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
self.canonical_cmp(other)
}
}
impl<Octets: AsRef<[u8]>> hash::Hash for Nsec3<Octets> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.hash_algorithm.hash(state);
self.flags.hash(state);
self.iterations.hash(state);
self.salt.hash(state);
self.next_owner.hash(state);
self.types.hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Nsec3<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let hash_algorithm = Nsec3HashAlg::parse(parser)?;
let flags = u8::parse(parser)?;
let iterations = u16::parse(parser)?;
let salt = Nsec3Salt::parse(parser)?;
let next_owner = OwnerHash::parse(parser)?;
let types = RtypeBitmap::parse(parser)?;
Ok(Self::new(
hash_algorithm,
flags,
iterations,
salt,
next_owner,
types,
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
Nsec3HashAlg::skip(parser)?;
u8::skip(parser)?;
u16::skip(parser)?;
Nsec3Salt::skip(parser)?;
OwnerHash::skip(parser)?;
RtypeBitmap::skip(parser)?;
Ok(())
}
}
impl<Octets: AsRef<[u8]>> Compose for Nsec3<Octets> {
fn compose<T: OctetsBuilder + AsMut<[u8]>>(
&self,
target: &mut T,
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.hash_algorithm.compose(buf)?;
self.flags.compose(buf)?;
self.iterations.compose(buf)?;
self.salt.compose(buf)?;
self.next_owner.compose(buf)?;
self.types.compose(buf)
})
}
}
#[cfg(feature = "master")]
impl Scan for Nsec3<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
Ok(Self::new(
Nsec3HashAlg::scan(scanner)?,
u8::scan(scanner)?,
u16::scan(scanner)?,
Nsec3Salt::scan(scanner)?,
OwnerHash::scan(scanner)?,
RtypeBitmap::scan(scanner)?,
))
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for Nsec3<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} {} {} {} ",
self.hash_algorithm, self.flags, self.iterations, self.salt
)?;
base32::display_hex(&self.next_owner, f)?;
write!(f, " {}", self.types)
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for Nsec3<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Nsec3")
.field("hash_algorithm", &self.hash_algorithm)
.field("flags", &self.flags)
.field("iterations", &self.iterations)
.field("salt", &self.salt)
.field("next_owner", &self.next_owner)
.field("types", &self.types)
.finish()
}
}
impl<Octets> RtypeRecordData for Nsec3<Octets> {
const RTYPE: Rtype = Rtype::Nsec3;
}
#[derive(Clone)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(bound(
serialize = "
Octets: crate::base::octets::SerializeOctets + AsRef<[u8]>,
",
deserialize = "
Octets: FromBuilder + crate::base::octets::DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
",
))
)]
pub struct Nsec3param<Octets> {
hash_algorithm: Nsec3HashAlg,
flags: u8,
iterations: u16,
salt: Nsec3Salt<Octets>,
}
impl<Octets> Nsec3param<Octets> {
pub fn new(
hash_algorithm: Nsec3HashAlg,
flags: u8,
iterations: u16,
salt: Nsec3Salt<Octets>,
) -> Self {
Nsec3param {
hash_algorithm,
flags,
iterations,
salt,
}
}
pub fn hash_algorithm(&self) -> Nsec3HashAlg {
self.hash_algorithm
}
pub fn flags(&self) -> u8 {
self.flags
}
pub fn iterations(&self) -> u16 {
self.iterations
}
pub fn salt(&self) -> &Nsec3Salt<Octets> {
&self.salt
}
}
impl<SrcOctets> Nsec3param<SrcOctets> {
pub fn flatten_into<Octets>(self) -> Result<Nsec3param<Octets>, PushError>
where
Octets: OctetsFrom<SrcOctets>,
{
let Self {
hash_algorithm,
flags,
iterations,
salt,
} = self;
Ok(Nsec3param::new(
hash_algorithm,
flags,
iterations,
salt.octets_into()?,
))
}
}
impl<Octets, SrcOctets> OctetsFrom<Nsec3param<SrcOctets>>
for Nsec3param<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(source: Nsec3param<SrcOctets>) -> Result<Self, ShortBuf> {
Ok(Nsec3param::new(
source.hash_algorithm,
source.flags,
source.iterations,
Nsec3Salt::octets_from(source.salt)?,
))
}
}
impl<Octets, Other> PartialEq<Nsec3param<Other>> for Nsec3param<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn eq(&self, other: &Nsec3param<Other>) -> bool {
self.hash_algorithm == other.hash_algorithm
&& self.flags == other.flags
&& self.iterations == other.iterations
&& self.salt == other.salt
}
}
impl<Octets: AsRef<[u8]>> Eq for Nsec3param<Octets> {}
impl<Octets, Other> PartialOrd<Nsec3param<Other>> for Nsec3param<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn partial_cmp(&self, other: &Nsec3param<Other>) -> Option<Ordering> {
match self.hash_algorithm.partial_cmp(&other.hash_algorithm) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.flags.partial_cmp(&other.flags) {
Some(Ordering::Equal) => {}
other => return other,
}
match self.iterations.partial_cmp(&other.iterations) {
Some(Ordering::Equal) => {}
other => return other,
}
self.salt.partial_cmp(&other.salt)
}
}
impl<Octets, Other> CanonicalOrd<Nsec3param<Other>> for Nsec3param<Octets>
where
Octets: AsRef<[u8]>,
Other: AsRef<[u8]>,
{
fn canonical_cmp(&self, other: &Nsec3param<Other>) -> Ordering {
match self.hash_algorithm.cmp(&other.hash_algorithm) {
Ordering::Equal => {}
other => return other,
}
match self.flags.cmp(&other.flags) {
Ordering::Equal => {}
other => return other,
}
match self.iterations.cmp(&other.iterations) {
Ordering::Equal => {}
other => return other,
}
self.salt.canonical_cmp(&other.salt)
}
}
impl<Octets: AsRef<[u8]>> Ord for Nsec3param<Octets> {
fn cmp(&self, other: &Self) -> Ordering {
match self.hash_algorithm.cmp(&other.hash_algorithm) {
Ordering::Equal => {}
other => return other,
}
match self.flags.cmp(&other.flags) {
Ordering::Equal => {}
other => return other,
}
match self.iterations.cmp(&other.iterations) {
Ordering::Equal => {}
other => return other,
}
self.salt.cmp(&other.salt)
}
}
impl<Octets: AsRef<[u8]>> hash::Hash for Nsec3param<Octets> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.hash_algorithm.hash(state);
self.flags.hash(state);
self.iterations.hash(state);
self.salt.hash(state);
}
}
impl<Ref: OctetsRef> Parse<Ref> for Nsec3param<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
Ok(Self::new(
Nsec3HashAlg::parse(parser)?,
u8::parse(parser)?,
u16::parse(parser)?,
Nsec3Salt::parse(parser)?,
))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
parser.advance(4)?;
Nsec3Salt::skip(parser)
}
}
impl<Octets: AsRef<[u8]>> Compose for Nsec3param<Octets> {
fn compose<T: OctetsBuilder + AsMut<[u8]>>(
&self,
target: &mut T,
) -> Result<(), ShortBuf> {
target.append_all(|buf| {
self.hash_algorithm.compose(buf)?;
self.flags.compose(buf)?;
self.iterations.compose(buf)?;
self.salt.compose(buf)
})
}
}
#[cfg(feature = "master")]
impl Scan for Nsec3param<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
Ok(Self::new(
Nsec3HashAlg::scan(scanner)?,
u8::scan(scanner)?,
u16::scan(scanner)?,
Nsec3Salt::scan(scanner)?,
))
}
}
impl<Octets: AsRef<[u8]>> fmt::Display for Nsec3param<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{} {} {} {}",
self.hash_algorithm, self.flags, self.iterations, self.salt
)
}
}
impl<Octets: AsRef<[u8]>> fmt::Debug for Nsec3param<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Nsec3param")
.field("hash_algorithm", &self.hash_algorithm)
.field("flags", &self.flags)
.field("iterations", &self.iterations)
.field("salt", &self.salt)
.finish()
}
}
impl<Octets> RtypeRecordData for Nsec3param<Octets> {
const RTYPE: Rtype = Rtype::Nsec3param;
}
#[derive(Clone)]
pub struct Nsec3Salt<Octets: ?Sized>(Octets);
impl<Octets: ?Sized> Nsec3Salt<Octets> {
pub fn empty() -> Self
where
Octets: From<&'static [u8]>,
{
Self(b"".as_ref().into())
}
pub fn from_octets(octets: Octets) -> Result<Self, Nsec3SaltError>
where
Octets: AsRef<[u8]> + Sized,
{
if octets.as_ref().len() > 255 {
Err(Nsec3SaltError)
} else {
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
unsafe fn from_octets_unchecked(octets: Octets) -> Self
where
Octets: Sized,
{
Self(octets)
}
pub fn into_octets(self) -> Octets
where
Octets: Sized,
{
self.0
}
pub fn as_slice(&self) -> &[u8]
where
Octets: AsRef<[u8]>,
{
self.0.as_ref()
}
}
#[cfg(feature = "bytes")]
#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
impl Nsec3Salt<Bytes> {
pub fn from_bytes(bytes: Bytes) -> Result<Self, Nsec3SaltError> {
Self::from_octets(bytes)
}
}
impl Nsec3Salt<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, Nsec3SaltError> {
if slice.len() > 255 {
Err(Nsec3SaltError)
} else {
Ok(unsafe { &*(slice as *const [u8] as *const Nsec3Salt<[u8]>) })
}
}
}
impl<Octets, SrcOctets> OctetsFrom<Nsec3Salt<SrcOctets>> for Nsec3Salt<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(source: Nsec3Salt<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.0)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Octets> str::FromStr for Nsec3Salt<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Err = base16::DecodeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s == "-" {
Ok(unsafe {
Self::from_octets_unchecked(Octets::Builder::empty().freeze())
})
} else {
base16::decode(s)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
}
impl<Octets: ?Sized> ops::Deref for Nsec3Salt<Octets> {
type Target = Octets;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<Octets: AsRef<U> + ?Sized, U: ?Sized> AsRef<U> for Nsec3Salt<Octets> {
fn as_ref(&self) -> &U {
self.0.as_ref()
}
}
impl<T, U> PartialEq<U> for Nsec3Salt<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn eq(&self, other: &U) -> bool {
self.as_slice().eq(other.as_ref())
}
}
impl<T: AsRef<[u8]> + ?Sized> Eq for Nsec3Salt<T> {}
impl<T, U> PartialOrd<U> for Nsec3Salt<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn partial_cmp(&self, other: &U) -> Option<Ordering> {
self.0.as_ref().partial_cmp(other.as_ref())
}
}
impl<T: AsRef<[u8]> + ?Sized> Ord for Nsec3Salt<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.as_ref().cmp(other.as_ref())
}
}
impl<T, U> CanonicalOrd<Nsec3Salt<U>> for Nsec3Salt<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn canonical_cmp(&self, other: &Nsec3Salt<U>) -> Ordering {
match self.0.as_ref().len().cmp(&other.0.as_ref().len()) {
Ordering::Equal => {}
other => return other,
}
self.as_slice().cmp(other.as_slice())
}
}
impl<T: AsRef<[u8]> + ?Sized> hash::Hash for Nsec3Salt<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state)
}
}
impl<Ref: OctetsRef> Parse<Ref> for Nsec3Salt<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let len = parser.parse_u8()? as usize;
parser
.parse_octets(len)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
let len = parser.parse_u8()? as usize;
parser.advance(len)
}
}
impl<Octets: AsRef<[u8]> + ?Sized> Compose for Nsec3Salt<Octets> {
fn compose<Target: OctetsBuilder + AsMut<[u8]>>(
&self,
target: &mut Target,
) -> Result<(), ShortBuf> {
target.append_all(|target| {
(self.as_ref().len() as u8).compose(target)?;
target.append_slice(self.as_ref())
})
}
}
#[cfg(feature = "master")]
impl Scan for Nsec3Salt<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
if let Ok(()) = scanner.skip_literal("-") {
Ok(Self::empty())
} else {
scanner.scan_hex_word(|b| unsafe {
Ok(Self::from_octets_unchecked(b))
})
}
}
}
impl<Octets: AsRef<[u8]> + ?Sized> fmt::Display for Nsec3Salt<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
base16::display(self.as_slice(), f)
}
}
impl<Octets: AsRef<[u8]> + ?Sized> fmt::Debug for Nsec3Salt<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Nsec3Salt")
.field(&format_args!("{}", self))
.finish()
}
}
#[cfg(feature = "serde")]
impl<T: AsRef<[u8]> + SerializeOctets> serde::Serialize for Nsec3Salt<T> {
fn serialize<S: serde::Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
serializer.serialize_newtype_struct(
"Nsec3Salt",
&format_args!("{}", self),
)
} else {
serializer.serialize_newtype_struct(
"Nsec3Salt",
&self.0.as_serialized_octets(),
)
}
}
}
#[cfg(feature = "serde")]
impl<'de, Octets> serde::Deserialize<'de> for Nsec3Salt<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
fn deserialize<D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
use core::marker::PhantomData;
use core::str::FromStr;
struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
impl<'de, Octets> serde::de::Visitor<'de> for InnerVisitor<'de, Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Value = Nsec3Salt<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an NSEC3 salt value")
}
fn visit_str<E: serde::de::Error>(
self,
v: &str,
) -> Result<Self::Value, E> {
Nsec3Salt::from_str(v).map_err(E::custom)
}
fn visit_borrowed_bytes<E: serde::de::Error>(
self,
value: &'de [u8],
) -> Result<Self::Value, E> {
self.0.visit_borrowed_bytes(value).and_then(|octets| {
Nsec3Salt::from_octets(octets).map_err(E::custom)
})
}
#[cfg(feature = "std")]
fn visit_byte_buf<E: serde::de::Error>(
self,
value: std::vec::Vec<u8>,
) -> Result<Self::Value, E> {
self.0.visit_byte_buf(value).and_then(|octets| {
Nsec3Salt::from_octets(octets).map_err(E::custom)
})
}
}
struct NewtypeVisitor<T>(PhantomData<T>);
impl<'de, Octets> serde::de::Visitor<'de> for NewtypeVisitor<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Value = Nsec3Salt<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an NSEC3 salt value")
}
fn visit_newtype_struct<D: serde::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
if deserializer.is_human_readable() {
deserializer
.deserialize_str(InnerVisitor(Octets::visitor()))
} else {
Octets::deserialize_with_visitor(
deserializer,
InnerVisitor(Octets::visitor()),
)
}
}
}
deserializer.deserialize_newtype_struct(
"Nsec3Salt",
NewtypeVisitor(PhantomData),
)
}
}
#[derive(Clone)]
pub struct OwnerHash<Octets: ?Sized>(Octets);
impl<Octets: ?Sized> OwnerHash<Octets> {
pub fn from_octets(octets: Octets) -> Result<Self, OwnerHashError>
where
Octets: AsRef<[u8]> + Sized,
{
if octets.as_ref().len() > 255 {
Err(OwnerHashError)
} else {
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
}
unsafe fn from_octets_unchecked(octets: Octets) -> Self
where
Octets: Sized,
{
Self(octets)
}
pub fn into_octets(self) -> Octets
where
Octets: Sized,
{
self.0
}
pub fn as_slice(&self) -> &[u8]
where
Octets: AsRef<[u8]>,
{
self.0.as_ref()
}
}
#[cfg(feature = "bytes")]
#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
impl OwnerHash<Bytes> {
pub fn from_bytes(bytes: Bytes) -> Result<Self, OwnerHashError> {
Self::from_octets(bytes)
}
}
impl OwnerHash<[u8]> {
pub fn from_slice(slice: &[u8]) -> Result<&Self, OwnerHashError> {
if slice.len() > 255 {
Err(OwnerHashError)
} else {
Ok(unsafe { &*(slice as *const [u8] as *const OwnerHash<[u8]>) })
}
}
}
impl<Octets, SrcOctets> OctetsFrom<OwnerHash<SrcOctets>> for OwnerHash<Octets>
where
Octets: OctetsFrom<SrcOctets>,
{
fn octets_from(source: OwnerHash<SrcOctets>) -> Result<Self, ShortBuf> {
Octets::octets_from(source.0)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Octets> str::FromStr for OwnerHash<Octets>
where
Octets: FromBuilder,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Err = base32::DecodeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
base32::decode_hex(s)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
impl<Octets: ?Sized> ops::Deref for OwnerHash<Octets> {
type Target = Octets;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<Octets: AsRef<U> + ?Sized, U: ?Sized> AsRef<U> for OwnerHash<Octets> {
fn as_ref(&self) -> &U {
self.0.as_ref()
}
}
impl<T, U> PartialEq<U> for OwnerHash<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn eq(&self, other: &U) -> bool {
self.as_slice().eq(other.as_ref())
}
}
impl<T: AsRef<[u8]> + ?Sized> Eq for OwnerHash<T> {}
impl<T, U> PartialOrd<U> for OwnerHash<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn partial_cmp(&self, other: &U) -> Option<Ordering> {
self.0.as_ref().partial_cmp(other.as_ref())
}
}
impl<T: AsRef<[u8]> + ?Sized> Ord for OwnerHash<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.as_ref().cmp(other.as_ref())
}
}
impl<T, U> CanonicalOrd<OwnerHash<U>> for OwnerHash<T>
where
T: AsRef<[u8]> + ?Sized,
U: AsRef<[u8]> + ?Sized,
{
fn canonical_cmp(&self, other: &OwnerHash<U>) -> Ordering {
match self.0.as_ref().len().cmp(&other.0.as_ref().len()) {
Ordering::Equal => {}
other => return other,
}
self.as_slice().cmp(other.as_slice())
}
}
impl<T: AsRef<[u8]> + ?Sized> hash::Hash for OwnerHash<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state)
}
}
impl<Ref: OctetsRef> Parse<Ref> for OwnerHash<Ref::Range> {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let len = parser.parse_u8()? as usize;
parser
.parse_octets(len)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
let len = parser.parse_u8()? as usize;
parser.advance(len)
}
}
impl<Octets: AsRef<[u8]> + ?Sized> Compose for OwnerHash<Octets> {
fn compose<Target: OctetsBuilder + AsMut<[u8]>>(
&self,
target: &mut Target,
) -> Result<(), ShortBuf> {
target.append_all(|target| {
(self.as_ref().len() as u8).compose(target)?;
target.append_slice(self.as_ref())
})
}
}
#[cfg(feature = "master")]
impl Scan for OwnerHash<Bytes> {
fn scan<C: CharSource>(
scanner: &mut Scanner<C>,
) -> Result<Self, ScanError> {
scanner.scan_base32hex_phrase(|b| unsafe {
Ok(Self::from_octets_unchecked(b))
})
}
}
impl<Octets: AsRef<[u8]> + ?Sized> fmt::Display for OwnerHash<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
base32::display_hex(self.as_slice(), f)
}
}
impl<Octets: AsRef<[u8]> + ?Sized> fmt::Debug for OwnerHash<Octets> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("OwnerHash")
.field(&format_args!("{}", self))
.finish()
}
}
#[cfg(feature = "serde")]
impl<T: AsRef<[u8]> + SerializeOctets> serde::Serialize for OwnerHash<T> {
fn serialize<S: serde::Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
serializer.serialize_newtype_struct(
"OwnerHash",
&format_args!("{}", self),
)
} else {
serializer.serialize_newtype_struct(
"OwnerHash",
&self.0.as_serialized_octets(),
)
}
}
}
#[cfg(feature = "serde")]
impl<'de, Octets> serde::Deserialize<'de> for OwnerHash<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
fn deserialize<D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
use core::marker::PhantomData;
use core::str::FromStr;
struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
impl<'de, Octets> serde::de::Visitor<'de> for InnerVisitor<'de, Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Value = OwnerHash<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an owner name hash value")
}
fn visit_str<E: serde::de::Error>(
self,
v: &str,
) -> Result<Self::Value, E> {
OwnerHash::from_str(v).map_err(E::custom)
}
fn visit_borrowed_bytes<E: serde::de::Error>(
self,
value: &'de [u8],
) -> Result<Self::Value, E> {
self.0.visit_borrowed_bytes(value).and_then(|octets| {
OwnerHash::from_octets(octets).map_err(E::custom)
})
}
#[cfg(feature = "std")]
fn visit_byte_buf<E: serde::de::Error>(
self,
value: std::vec::Vec<u8>,
) -> Result<Self::Value, E> {
self.0.visit_byte_buf(value).and_then(|octets| {
OwnerHash::from_octets(octets).map_err(E::custom)
})
}
}
struct NewtypeVisitor<T>(PhantomData<T>);
impl<'de, Octets> serde::de::Visitor<'de> for NewtypeVisitor<Octets>
where
Octets: FromBuilder + DeserializeOctets<'de>,
<Octets as FromBuilder>::Builder:
OctetsBuilder<Octets = Octets> + EmptyBuilder,
{
type Value = OwnerHash<Octets>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("an owner name hash value")
}
fn visit_newtype_struct<D: serde::Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Self::Value, D::Error> {
if deserializer.is_human_readable() {
deserializer
.deserialize_str(InnerVisitor(Octets::visitor()))
} else {
Octets::deserialize_with_visitor(
deserializer,
InnerVisitor(Octets::visitor()),
)
}
}
}
deserializer.deserialize_newtype_struct(
"OwnerHash",
NewtypeVisitor(PhantomData),
)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Nsec3SaltError;
impl fmt::Display for Nsec3SaltError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("illegal NSEC3 salt")
}
}
#[cfg(feature = "std")]
impl std::error::Error for Nsec3SaltError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OwnerHashError;
impl fmt::Display for OwnerHashError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("illegal owner name hash")
}
}
#[cfg(feature = "std")]
impl std::error::Error for OwnerHashError {}