use core::{
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
};
use domain_macros::UnsizedCopy;
use crate::new::base::{
build::{BuildInMessage, NameCompressor},
parse::{ParseMessageBytes, SplitMessageBytes},
};
use super::{
AsBytes, BuildBytes, ParseBytes, ParseBytesZC, ParseError, SplitBytes,
SplitBytesZC, TruncationError,
};
#[derive(Copy, Clone, AsBytes, UnsizedCopy)]
#[repr(C)]
pub struct SizePrefixed<S, T: ?Sized> {
size: S,
data: T,
}
impl<S, T> SizePrefixed<S, T>
where
S: TryFrom<usize>,
{
pub fn new(data: T) -> Self {
let size = core::mem::size_of::<T>();
Self {
size: S::try_from(size).unwrap_or_else(|_| {
panic!(
"`data.len()` ({} bytes) overflows {}",
size,
core::any::type_name::<S>(),
)
}),
data,
}
}
}
impl<S, T> SizePrefixed<S, T> {
pub fn into_data(self) -> T {
self.data
}
}
impl<S, T: ?Sized> Deref for SizePrefixed<S, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<S, T: ?Sized> DerefMut for SizePrefixed<S, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<S, T: ?Sized> Borrow<T> for SizePrefixed<S, T> {
fn borrow(&self) -> &T {
&self.data
}
}
impl<S, T: ?Sized> BorrowMut<T> for SizePrefixed<S, T> {
fn borrow_mut(&mut self) -> &mut T {
&mut self.data
}
}
impl<S, T: ?Sized> AsRef<T> for SizePrefixed<S, T> {
fn as_ref(&self) -> &T {
&self.data
}
}
impl<S, T: ?Sized> AsMut<T> for SizePrefixed<S, T> {
fn as_mut(&mut self) -> &mut T {
&mut self.data
}
}
impl<S, T: ?Sized + PartialEq> PartialEq for SizePrefixed<S, T> {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}
impl<S, T: ?Sized + Eq> Eq for SizePrefixed<S, T> {}
impl<S, T: ?Sized + PartialOrd> PartialOrd for SizePrefixed<S, T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.data.partial_cmp(&other.data)
}
}
impl<S, T: ?Sized + Ord> Ord for SizePrefixed<S, T> {
fn cmp(&self, other: &Self) -> Ordering {
self.data.cmp(&other.data)
}
}
impl<S, T: ?Sized + Hash> Hash for SizePrefixed<S, T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.data.hash(state)
}
}
impl<S, T: ?Sized + fmt::Debug> fmt::Debug for SizePrefixed<S, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SizePrefixed").field(&&self.data).finish()
}
}
impl<'b, S, T: ParseMessageBytes<'b>> ParseMessageBytes<'b>
for SizePrefixed<S, T>
where
S: SplitMessageBytes<'b> + TryFrom<usize> + Into<usize>,
{
fn parse_message_bytes(
contents: &'b [u8],
start: usize,
) -> Result<Self, ParseError> {
let (size, rest) = S::split_message_bytes(contents, start)?;
if rest + size.into() != contents.len() {
return Err(ParseError);
}
T::parse_message_bytes(contents, rest).map(Self::new)
}
}
impl<'b, S, T: ParseMessageBytes<'b>> SplitMessageBytes<'b>
for SizePrefixed<S, T>
where
S: SplitMessageBytes<'b> + TryFrom<usize> + Into<usize>,
{
fn split_message_bytes(
contents: &'b [u8],
start: usize,
) -> Result<(Self, usize), ParseError> {
let (size, rest) = S::split_message_bytes(contents, start)?;
let (start, rest) = (rest, rest + size.into());
let contents = contents.get(..rest).ok_or(ParseError)?;
let data = T::parse_message_bytes(contents, start)?;
Ok((Self::new(data), rest))
}
}
impl<'b, S, T: ParseBytes<'b>> ParseBytes<'b> for SizePrefixed<S, T>
where
S: SplitBytes<'b> + TryFrom<usize> + Into<usize>,
{
fn parse_bytes(bytes: &'b [u8]) -> Result<Self, ParseError> {
let (size, rest) = S::split_bytes(bytes)?;
if rest.len() != size.into() {
return Err(ParseError);
}
T::parse_bytes(bytes).map(Self::new)
}
}
impl<'b, S, T: ParseBytes<'b>> SplitBytes<'b> for SizePrefixed<S, T>
where
S: SplitBytes<'b> + TryFrom<usize> + Into<usize>,
{
fn split_bytes(bytes: &'b [u8]) -> Result<(Self, &'b [u8]), ParseError> {
let (size, rest) = S::split_bytes(bytes)?;
let size: usize = size.into();
if rest.len() < size {
return Err(ParseError);
}
let (data, rest) = rest.split_at(size);
let data = T::parse_bytes(data)?;
Ok((Self::new(data), rest))
}
}
unsafe impl<S, T: ?Sized + ParseBytesZC> ParseBytesZC for SizePrefixed<S, T>
where
S: SplitBytesZC + Copy + Into<usize>,
{
fn parse_bytes_by_ref(bytes: &[u8]) -> Result<&Self, ParseError> {
let addr = bytes.as_ptr();
let (size, rest) = S::split_bytes_by_ref(bytes)?;
if rest.len() != (*size).into() {
return Err(ParseError);
}
let last = T::parse_bytes_by_ref(rest)?;
let ptr = last.ptr_with_addr(addr as *const ());
Ok(unsafe { &*(ptr as *const Self) })
}
}
unsafe impl<S, T: ?Sized + ParseBytesZC> SplitBytesZC for SizePrefixed<S, T>
where
S: SplitBytesZC + Copy + Into<usize>,
{
fn split_bytes_by_ref(
bytes: &[u8],
) -> Result<(&Self, &[u8]), ParseError> {
let addr = bytes.as_ptr();
let (&size, rest) = S::split_bytes_by_ref(bytes)?;
if rest.len() < size.into() {
return Err(ParseError);
}
let (data, rest) = rest.split_at(size.into());
let last = T::parse_bytes_by_ref(data)?;
let ptr = last.ptr_with_addr(addr as *const ());
Ok((unsafe { &*(ptr as *const Self) }, rest))
}
}
impl<S, T: ?Sized + BuildInMessage> BuildInMessage for SizePrefixed<S, T>
where
S: AsBytes + Default + TryFrom<usize>,
{
fn build_in_message(
&self,
contents: &mut [u8],
start: usize,
name: &mut NameCompressor,
) -> Result<usize, TruncationError> {
let data_start = start + core::mem::size_of::<S>();
if contents.len() < data_start {
return Err(TruncationError);
}
let end = self.data.build_in_message(contents, data_start, name)?;
let size = end - data_start;
let size = S::try_from(size).unwrap_or_else(|_| {
panic!(
"`data.len()` ({} bytes) overflows {}",
size,
core::any::type_name::<S>(),
)
});
contents[start..data_start].copy_from_slice(size.as_bytes());
Ok(end)
}
}
impl<S, T: ?Sized + BuildBytes> BuildBytes for SizePrefixed<S, T>
where
S: AsBytes + Default + TryFrom<usize>,
{
fn build_bytes<'b>(
&self,
bytes: &'b mut [u8],
) -> Result<&'b mut [u8], TruncationError> {
let data_start = core::mem::size_of::<S>();
if bytes.len() < data_start {
return Err(TruncationError);
}
let (size_bytes, data_bytes) = bytes.split_at_mut(data_start);
let data_bytes_len = data_bytes.len();
let rest = self.data.build_bytes(data_bytes)?;
let size = data_bytes_len - rest.len();
let size = S::try_from(size).unwrap_or_else(|_| {
panic!(
"`data.len()` ({} bytes) overflows {}",
size,
core::any::type_name::<S>(),
)
});
size_bytes.copy_from_slice(size.as_bytes());
Ok(rest)
}
fn built_bytes_size(&self) -> usize {
core::mem::size_of::<S>() + self.data.built_bytes_size()
}
}