use core::fmt;
pub trait BuildBytes {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError>;
fn built_bytes_size(&self) -> usize;
}
macro_rules! impl_build_bytes_for_deref {
{$(
$(#[$attr:meta])*
impl[$($args:tt)*] BuildBytes for $subject:ty;
)*} => {$(
$(#[$attr])*
impl<$($args)*> BuildBytes for $subject {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
(**self).build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
(**self).built_bytes_size()
}
}
)*};
}
impl_build_bytes_for_deref! {
impl[T: ?Sized + BuildBytes] BuildBytes for &T;
impl[T: ?Sized + BuildBytes] BuildBytes for &mut T;
#[cfg(feature = "alloc")]
impl[T: ?Sized + BuildBytes] BuildBytes for alloc::boxed::Box<T>;
#[cfg(feature = "alloc")]
impl[T: ?Sized + BuildBytes] BuildBytes for alloc::rc::Rc<T>;
#[cfg(feature = "alloc")]
impl[T: ?Sized + BuildBytes] BuildBytes for alloc::sync::Arc<T>;
#[cfg(feature = "alloc")]
impl[] BuildBytes for alloc::string::String;
#[cfg(feature = "alloc")]
impl[T: BuildBytes] BuildBytes for alloc::vec::Vec<T>;
}
impl BuildBytes for () {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
Ok(bytes)
}
fn built_bytes_size(&self) -> usize {
0
}
}
impl BuildBytes for u8 {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
if let Some((elem, rest)) = bytes.split_first_mut() {
*elem = *self;
Ok(rest)
} else {
Err(TruncationError)
}
}
fn built_bytes_size(&self) -> usize {
1
}
}
impl BuildBytes for str {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
self.as_bytes().build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
self.len()
}
}
impl<T: BuildBytes> BuildBytes for [T] {
fn build_bytes<'b>(
&self,
mut bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
for elem in self {
bytes = elem.build_bytes(bytes)?;
}
Ok(bytes)
}
fn built_bytes_size(&self) -> usize {
self.iter().map(|e| e.built_bytes_size()).sum()
}
}
impl<T: BuildBytes, const N: usize> BuildBytes for [T; N] {
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
self.as_slice().build_bytes(bytes)
}
fn built_bytes_size(&self) -> usize {
self.as_slice().built_bytes_size()
}
}
pub use domain_macros::BuildBytes;
pub unsafe trait AsBytes {
fn as_bytes(&self) -> &[u8] {
unsafe {
core::slice::from_raw_parts(
self as *const Self as *const u8,
core::mem::size_of_val(self),
)
}
}
}
unsafe impl AsBytes for u8 {}
unsafe impl AsBytes for str {}
unsafe impl<T: AsBytes> AsBytes for [T] {}
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
pub use domain_macros::AsBytes;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TruncationError;
#[cfg(feature = "std")]
impl std::error::Error for TruncationError {}
impl fmt::Display for TruncationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("an object was too large to be serialized")
}
}