use crate::{tss2_esys::UINT32, Result};
use std::convert::TryFrom;
pub trait Marshall: Sized {
const BUFFER_SIZE: usize;
fn marshall(&self) -> Result<Vec<u8>> {
let mut buffer = vec![0; Self::BUFFER_SIZE];
let mut offset = 0;
self.marshall_offset(&mut buffer, &mut offset)?;
buffer.truncate(offset);
Ok(buffer)
}
fn marshall_offset(&self, _marshalled_data: &mut [u8], _offset: &mut usize) -> Result<()> {
unimplemented!();
}
}
pub trait UnMarshall: Sized {
fn unmarshall(marshalled_data: &[u8]) -> Result<Self> {
Self::unmarshall_offset(marshalled_data, &mut 0)
}
fn unmarshall_offset(_marshalled_data: &[u8], _offset: &mut usize) -> Result<Self> {
unimplemented!();
}
}
macro_rules! impl_marshall_trait {
($native_type:ident, $tss_type:ident, $tss_mu_type:ident, $convert_expression:stmt, $( $ref_sign:tt )?) => {
paste::item! {
impl $crate::traits::Marshall for $native_type {
const BUFFER_SIZE: usize = std::mem::size_of::<$tss_type>();
fn marshall_offset(
&self,
marshalled_data: &mut [u8],
offset: &mut usize,
) -> $crate::Result<()> {
let ffi_object = self.clone().$convert_expression;
let ffi_buffer_size = $crate::ffi::FfiSizeType::try_from(marshalled_data.len())?;
let mut ffi_offset = $crate::ffi::FfiSizeType::try_from(*offset)?;
$crate::ReturnCode::ensure_success(
unsafe {
$crate::tss2_esys::[< Tss2_MU_ $tss_mu_type _Marshal >](
$( $ref_sign )?ffi_object,
marshalled_data.as_mut_ptr(),
ffi_buffer_size.into(),
ffi_offset.as_mut_ptr(),
)
},
|ret| {
log::error!(
"Failed to marshall {}: {}",
std::stringify!($native_type),
ret
);
},
)?;
*offset = usize::try_from(ffi_offset)?;
Ok(())
}
}
}
};
}
macro_rules! impl_unmarshall_trait {
($native_type:ident, $tss_type:ident, $tss_mu_type:ident, $convert_expression:expr) => {
paste::item! {
impl $crate::traits::UnMarshall for $native_type {
fn unmarshall_offset(marshalled_data: &[u8], offset: &mut usize) -> Result<Self> {
let mut dest = $tss_type::default();
let ffi_buffer_size = $crate::ffi::FfiSizeType::try_from(marshalled_data.len())?;
let mut ffi_offset = $crate::ffi::FfiSizeType::try_from(*offset)?;
crate::ReturnCode::ensure_success(
unsafe {
crate::tss2_esys::[ < Tss2_MU_ $tss_mu_type _Unmarshal >](
marshalled_data.as_ptr(),
ffi_buffer_size.into(),
ffi_offset.as_mut_ptr(),
&mut dest,
)
},
|ret| log::error!("Failed to unmarshal {}: {}", std::stringify!($native_type), ret),
)?;
*offset = usize::try_from(ffi_offset)?;
$convert_expression(dest)
}
}
}
};
}
macro_rules! impl_mu_aliases {
($tss_type:ident) => {
$crate::traits::impl_marshall_trait!($tss_type, $tss_type, $tss_type, into(),);
$crate::traits::impl_unmarshall_trait!($tss_type, $tss_type, $tss_type, Ok);
};
}
macro_rules! impl_mu_simple {
($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
$crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, into(),);
$crate::traits::impl_unmarshall_trait!(
$native_type,
$tss_type,
$tss_mu_type,
$native_type::try_from
);
};
($native_type:ident, $tss_type:ident) => {
$crate::traits::impl_mu_simple!($native_type, $tss_type, $tss_type);
};
}
macro_rules! impl_mu_standard {
($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
$crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, into(), &);
$crate::traits::impl_unmarshall_trait!(
$native_type,
$tss_type,
$tss_mu_type,
$native_type::try_from
);
};
($native_type:ident, $tss_type:ident) => {
$crate::traits::impl_mu_standard!($native_type, $tss_type, $tss_type);
};
}
macro_rules! impl_mu_complex {
($native_type:ident, $tss_type:ident, $tss_mu_type:ident) => {
$crate::traits::impl_marshall_trait!($native_type, $tss_type, $tss_mu_type, try_into()?, &);
$crate::traits::impl_unmarshall_trait!(
$native_type,
$tss_type,
$tss_mu_type,
$native_type::try_from
);
};
($native_type:ident, $tss_type:ident) => {
$crate::traits::impl_mu_complex!($native_type, $tss_type, $tss_type);
};
}
pub(crate) use impl_marshall_trait;
pub(crate) use impl_mu_aliases;
pub(crate) use impl_mu_complex;
pub(crate) use impl_mu_simple;
pub(crate) use impl_mu_standard;
pub(crate) use impl_unmarshall_trait;
impl_mu_aliases!(UINT32);