use core::hash::{Hash, Hasher};
use core::{cmp::Ordering, fmt};
use crate::new::base::build::BuildInMessage;
use crate::new::base::name::{CanonicalName, Name, NameCompressor};
use crate::new::base::wire::*;
use crate::new::base::{CanonicalRecordData, RType};
use crate::utils::dst::UnsizedCopy;
#[derive(Clone, Debug, PartialEq, Eq, Hash, BuildBytes)]
pub struct NSec<'a> {
pub next: &'a Name,
pub types: &'a TypeBitmaps,
}
impl NSec<'_> {
#[cfg(feature = "bumpalo")]
pub fn clone_to_bump<'r>(&self, bump: &'r bumpalo::Bump) -> NSec<'r> {
use crate::utils::dst::copy_to_bump;
NSec {
next: copy_to_bump(self.next, bump),
types: copy_to_bump(self.types, bump),
}
}
}
impl CanonicalRecordData for NSec<'_> {
fn cmp_canonical(&self, other: &Self) -> Ordering {
self.next
.cmp_composed(other.next)
.then_with(|| self.types.as_bytes().cmp(other.types.as_bytes()))
}
}
impl BuildInMessage for NSec<'_> {
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
_compressor: &mut NameCompressor,
) -> Result<usize, TruncationError> {
let bytes = contents.get_mut(start..).ok_or(TruncationError)?;
let rest = self.build_bytes(bytes)?.len();
Ok(contents.len() - rest)
}
}
impl<'a> ParseBytes<'a> for NSec<'a> {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
let (next, bytes) = <&Name>::split_bytes(bytes)?;
if bytes.is_empty() {
return Err(ParseError);
}
let types = <&TypeBitmaps>::parse_bytes(bytes)?;
Ok(Self { next, types })
}
}
#[derive(PartialEq, Eq, AsBytes, BuildBytes, UnsizedCopy)]
#[repr(transparent)]
pub struct TypeBitmaps {
octets: [u8],
}
impl TypeBitmaps {
pub fn types(&self) -> impl Iterator<Item = RType> + '_ {
fn split_window(octets: &[u8]) -> Option<(u8, &[u8], &[u8])> {
let &[num, len, ref rest @ ..] = octets else {
return None;
};
let (bits, rest) = rest.split_at(len as usize);
Some((num, bits, rest))
}
core::iter::successors(split_window(&self.octets), |(_, _, rest)| {
split_window(rest)
})
.flat_map(move |(num, bits, _)| {
bits.iter().enumerate().flat_map(move |(i, &b)| {
(0..8).filter(move |&j| ((b >> j) & 1) != 0).map(move |j| {
RType::from(u16::from_be_bytes([num, (i * 8 + j) as u8]))
})
})
})
}
}
impl fmt::Debug for TypeBitmaps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.types()).finish()
}
}
impl TypeBitmaps {
fn validate_bytes(mut octets: &[u8]) -> Result<(), ParseError> {
let mut num = None;
while let Some(&next) = octets.first() {
if num.replace(next) > Some(next) {
return Err(ParseError);
}
octets = Self::validate_window_bytes(octets)?;
}
Ok(())
}
fn validate_window_bytes(octets: &[u8]) -> Result<&[u8], ParseError> {
let &[_num, len, ref rest @ ..] = octets else {
return Err(ParseError);
};
if !(1..=32).contains(&len) || rest.len() < len as usize {
return Err(ParseError);
}
let (bits, rest) = rest.split_at(len as usize);
if bits.last() == Some(&0) {
return Err(ParseError);
}
Ok(rest)
}
}
unsafe impl ParseBytesZC for TypeBitmaps {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
Self::validate_bytes(bytes)?;
unsafe { core::mem::transmute(bytes) }
}
}
#[cfg(feature = "alloc")]
impl Clone for alloc::boxed::Box<TypeBitmaps> {
fn clone(&self) -> Self {
(*self).unsized_copy_into()
}
}
impl Hash for TypeBitmaps {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.octets)
}
}