use crate::{
TpmiAlgHash,
errors::{MarshalError, UnmarshalError},
};
use core::convert::Infallible;
pub trait Limits: Copy {
fn supports_hash(self, h: TpmiAlgHash) -> bool;
fn max_digest_size(self) -> usize {
for &h in TpmiAlgHash::BY_SIZE_DESC {
if self.supports_hash(h) {
return h.digest_size();
}
}
0
}
}
pub trait Marshal {
fn marshal<'dst>(
&self,
limits: impl Limits,
buf: &'dst mut [u8],
) -> Result<&'dst mut [u8], MarshalError>;
fn marshaled_size(&self) -> usize;
fn marshaled_size_max(limits: impl Limits) -> usize;
}
pub trait Unmarshal<'src> {
fn unmarshal(
&mut self,
limits: impl Limits,
buf: &'src [u8],
) -> Result<&'src [u8], UnmarshalError>;
}
pub trait MarshalArray: Marshal {
const SIZE: usize;
type Array;
fn marshal_array(&self, arr: &mut Self::Array);
}
impl<T: MarshalArray<Array = [u8; N]>, const N: usize> Marshal for T {
#[inline(always)]
fn marshal<'dst>(
&self,
_: impl Limits,
buf: &'dst mut [u8],
) -> Result<&'dst mut [u8], MarshalError> {
let (arr, buf) = buf.split_first_chunk_mut().ok_or(MarshalError)?;
self.marshal_array(arr);
Ok(buf)
}
#[inline(always)]
fn marshaled_size(&self) -> usize {
Self::SIZE
}
#[inline(always)]
fn marshaled_size_max(_: impl Limits) -> usize {
Self::SIZE
}
}
pub trait UnmarshalArray: Sized + MarshalArray + for<'src> Unmarshal<'src>
where
UnmarshalError: From<Self::Error>,
{
type Error;
fn unmarshal_array(arr: &Self::Array) -> Result<Self, Self::Error>;
}
impl<'src, T: UnmarshalArray<Array = [u8; N]>, const N: usize> Unmarshal<'src> for T
where
UnmarshalError: From<T::Error>,
{
#[inline(always)]
fn unmarshal(&mut self, _: impl Limits, buf: &'src [u8]) -> Result<&'src [u8], UnmarshalError> {
let (arr, buf) = buf.split_first_chunk().ok_or(UnmarshalError)?;
*self = Self::unmarshal_array(arr)?;
Ok(buf)
}
}
macro_rules! impl_ints { ($($T: ty),+) => { $(
impl MarshalArray for $T {
const SIZE: usize = size_of::<Self>();
type Array = [u8; size_of::<Self>()];
fn marshal_array(&self, arr: &mut [u8; Self::SIZE]) {
*arr = self.to_be_bytes();
}
}
impl UnmarshalArray for $T {
type Error = Infallible;
fn unmarshal_array(arr: &[u8; Self::SIZE]) -> Result<Self, Infallible> {
Ok(Self::from_be_bytes(*arr))
}
}
)+ } }
impl_ints!(u8, u16, u32, u64, i8, i16, i32, i64);
impl<const N: usize> MarshalArray for [u8; N] {
const SIZE: usize = N;
type Array = [u8; N];
#[inline(always)]
fn marshal_array(&self, arr: &mut [u8; N]) {
*arr = *self;
}
}