use core::fmt;
use core::mem::MaybeUninit;
use crate::utils::dst::UnsizedCopy;
pub trait ParseBytes<'a>: Sized {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError>;
}
impl<'a> ParseBytes<'a> for u8 {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
let [result] = bytes else {
return Err(ParseError);
};
Ok(*result)
}
}
impl<'a, T: ?Sized + ParseBytesZC> ParseBytes<'a> for &'a T {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
T::parse_bytes_by_ref(bytes).map_err(|_| ParseError)
}
}
impl<'a, T: SplitBytes<'a>, const N: usize> ParseBytes<'a> for [T; N] {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
match Self::split_bytes(bytes) {
Ok((this, &[])) => Ok(this),
_ => Err(ParseError),
}
}
}
#[cfg(feature = "alloc")]
impl<'a, T: ParseBytes<'a>> ParseBytes<'a> for alloc::boxed::Box<T> {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
T::parse_bytes(bytes).map(alloc::boxed::Box::new)
}
}
#[cfg(feature = "alloc")]
impl<'a> ParseBytes<'a> for alloc::vec::Vec<u8> {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
Ok(bytes.to_vec())
}
}
#[cfg(feature = "alloc")]
impl<'a> ParseBytes<'a> for alloc::string::String {
fn parse_bytes(bytes: &'a [u8]) -> Result<Self, ParseError> {
str::parse_bytes_by_ref(bytes).map(alloc::string::String::from)
}
}
pub use domain_macros::ParseBytes;
pub trait SplitBytes<'a>: Sized + ParseBytes<'a> {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError>;
}
impl<'a> SplitBytes<'a> for u8 {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
bytes.split_first().map(|(&f, r)| (f, r)).ok_or(ParseError)
}
}
impl<'a, T: ?Sized + SplitBytesZC> SplitBytes<'a> for &'a T {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
T::split_bytes_by_ref(bytes).map_err(|_| ParseError)
}
}
impl<'a, T: SplitBytes<'a>, const N: usize> SplitBytes<'a> for [T; N] {
fn split_bytes(
mut bytes: &'a [u8],
) -> Result<(Self, &'a [u8]), ParseError> {
struct Guard<T, const N: usize> {
buffer: [MaybeUninit<T>; N],
initialized: usize,
}
impl<T, const N: usize> Drop for Guard<T, N> {
fn drop(&mut self) {
for elem in &mut self.buffer[..self.initialized] {
unsafe { elem.assume_init_drop() };
}
}
}
let mut guard = Guard::<T, N> {
buffer: [const { MaybeUninit::uninit() }; N],
initialized: 0,
};
while guard.initialized < N {
let (elem, rest) = T::split_bytes(bytes)?;
guard.buffer[guard.initialized].write(elem);
bytes = rest;
guard.initialized += 1;
}
guard.initialized = 0;
Ok((unsafe { core::mem::transmute_copy(&guard.buffer) }, bytes))
}
}
#[cfg(feature = "alloc")]
impl<'a, T: SplitBytes<'a>> SplitBytes<'a> for alloc::boxed::Box<T> {
fn split_bytes(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), ParseError> {
T::split_bytes(bytes)
.map(|(this, rest)| (alloc::boxed::Box::new(this), rest))
}
}
pub use domain_macros::SplitBytes;
pub unsafe trait ParseBytesZC: UnsizedCopy + 'static {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError>;
#[inline]
fn parse_bytes_in<C: ParseBytesInPlace>(
container: C,
) -> Result<C::WithParsed<Self>, (C, ParseError)> {
C::parse_bytes_in_place(container)
}
}
unsafe impl ParseBytesZC for u8 {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
if let [result] = bytes {
Ok(result)
} else {
Err(ParseError)
}
}
}
unsafe impl ParseBytesZC for [u8] {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
Ok(bytes)
}
}
unsafe impl ParseBytesZC for str {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
core::str::from_utf8(bytes).map_err(|_| ParseError)
}
}
unsafe impl<T: SplitBytesZC, const N: usize> ParseBytesZC for [T; N] {
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
let (this, rest) = Self::split_bytes_by_ref(bytes)?;
if rest.is_empty() {
Ok(this)
} else {
Err(ParseError)
}
}
}
pub use domain_macros::ParseBytesZC;
pub unsafe trait SplitBytesZC: ParseBytesZC {
fn split_bytes_by_ref(bytes: &[u8])
-> Result<(&Self, &[u8]), ParseError>;
}
unsafe impl SplitBytesZC for u8 {
fn split_bytes_by_ref(
bytes: &[u8],
) -> Result<(&Self, &[u8]), ParseError> {
bytes.split_first().ok_or(ParseError)
}
}
unsafe impl<T: SplitBytesZC, const N: usize> SplitBytesZC for [T; N] {
fn split_bytes_by_ref(
mut bytes: &[u8],
) -> Result<(&Self, &[u8]), ParseError> {
let start = bytes.as_ptr();
for _ in 0..N {
(_, bytes) = T::split_bytes_by_ref(bytes)?;
}
Ok((unsafe { &*start.cast::<[T; N]>() }, bytes))
}
}
pub use domain_macros::SplitBytesZC;
pub trait ParseBytesInPlace: Sized {
type WithParsed<T: ?Sized + ParseBytesZC>: Sized;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)>;
}
impl<'a> ParseBytesInPlace for &'a [u8] {
type WithParsed<T: ?Sized + ParseBytesZC> = &'a T;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)> {
T::parse_bytes_by_ref(self).map_err(|err| (self, err))
}
}
impl<'a> ParseBytesInPlace for &'a mut [u8] {
type WithParsed<T: ?Sized + ParseBytesZC> = &'a mut T;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)> {
let parsed = match T::parse_bytes_by_ref(self) {
Ok(parsed) => parsed as *const T,
Err(err) => return Err((self, err)),
};
Ok(unsafe { &mut *parsed.cast_mut() })
}
}
#[cfg(feature = "alloc")]
impl ParseBytesInPlace for alloc::boxed::Box<[u8]> {
type WithParsed<T: ?Sized + ParseBytesZC> = alloc::boxed::Box<T>;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)> {
let parsed = match T::parse_bytes_by_ref(&self) {
Ok(parsed) => parsed as *const T,
Err(err) => return Err((self, err)),
};
let _ = alloc::boxed::Box::into_raw(self);
Ok(unsafe { alloc::boxed::Box::from_raw(parsed.cast_mut()) })
}
}
#[cfg(feature = "alloc")]
impl ParseBytesInPlace for alloc::rc::Rc<[u8]> {
type WithParsed<T: ?Sized + ParseBytesZC> = alloc::rc::Rc<T>;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)> {
let parsed = match T::parse_bytes_by_ref(&self) {
Ok(parsed) => parsed as *const T,
Err(err) => return Err((self, err)),
};
let _ = alloc::rc::Rc::into_raw(self);
Ok(unsafe { alloc::rc::Rc::from_raw(parsed) })
}
}
#[cfg(feature = "alloc")]
impl ParseBytesInPlace for alloc::sync::Arc<[u8]> {
type WithParsed<T: ?Sized + ParseBytesZC> = alloc::sync::Arc<T>;
fn parse_bytes_in_place<T: ?Sized + ParseBytesZC>(
self,
) -> Result<Self::WithParsed<T>, (Self, ParseError)> {
let parsed = match T::parse_bytes_by_ref(&self) {
Ok(parsed) => parsed as *const T,
Err(err) => return Err((self, err)),
};
let _ = alloc::sync::Arc::into_raw(self);
Ok(unsafe { alloc::sync::Arc::from_raw(parsed) })
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ParseError;
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("DNS data could not be parsed from the wire format")
}
}