2023-03-21 14:53:59 +00:00
|
|
|
use std::{io::ErrorKind, marker::PhantomData};
|
2023-03-17 08:22:04 +00:00
|
|
|
|
2023-03-21 14:53:59 +00:00
|
|
|
use crate::{error::Error, HaskellSize};
|
2023-03-17 08:22:04 +00:00
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Main class definition
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
const ERROR_NOT_ALL_BYTES_READ: &str = "Not all bytes read";
|
|
|
|
|
|
|
|
pub trait FromHaskell<Tag>: Sized {
|
|
|
|
/// Deserialize data sent from Haskell
|
|
|
|
///
|
|
|
|
/// This is the analogue of `BorshDeserialize::deserialize`.
|
|
|
|
//
|
|
|
|
/// See `ToHaskell` for a detailed discussion of the `tag` argument.
|
|
|
|
fn from_haskell(buf: &mut &[u8], tag: PhantomData<Tag>) -> Result<Self, Error>;
|
|
|
|
|
|
|
|
fn from_haskell_slice(slice: &[u8], tag: PhantomData<Tag>) -> Result<Self, Error> {
|
|
|
|
let mut slice_mut = slice;
|
|
|
|
let result = Self::from_haskell(&mut slice_mut, tag)?;
|
|
|
|
if !slice_mut.is_empty() {
|
2023-03-21 14:53:59 +00:00
|
|
|
return Err(Box::new(std::io::Error::new(
|
|
|
|
ErrorKind::InvalidData,
|
|
|
|
ERROR_NOT_ALL_BYTES_READ,
|
|
|
|
)));
|
2023-03-17 08:22:04 +00:00
|
|
|
}
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
Derived functionality
|
|
|
|
|
|
|
|
See comments in `to_haskell` for why these functions do not live inside the
|
|
|
|
trait.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
/// Marshall value with variable-sized encoding
|
|
|
|
pub fn marshall_from_haskell_var<Tag, T>(inp: *const u8, len: usize, tag: PhantomData<Tag>) -> T
|
|
|
|
where
|
|
|
|
T: FromHaskell<Tag>,
|
|
|
|
{
|
|
|
|
let mut vec: Vec<u8> = vec![0; len];
|
|
|
|
unsafe {
|
|
|
|
std::ptr::copy(inp, vec.as_mut_ptr(), len);
|
|
|
|
}
|
|
|
|
match T::from_haskell_slice(vec.as_ref(), tag) {
|
|
|
|
Ok(t) => t,
|
|
|
|
Err(e) => panic!("{}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Marshall value with fixed-size encoding
|
|
|
|
///
|
|
|
|
/// The `len` argument here is only to verify that the Haskell-side and
|
|
|
|
/// Rust-side agree on the size of the encoding.
|
|
|
|
pub fn marshall_from_haskell_fixed<Tag, T>(
|
|
|
|
inp: *const u8,
|
|
|
|
inp_len: usize,
|
|
|
|
tag: PhantomData<Tag>,
|
|
|
|
) -> T
|
|
|
|
where
|
|
|
|
T: FromHaskell<Tag> + HaskellSize<Tag>,
|
|
|
|
{
|
|
|
|
let expected_len = T::haskell_size(tag);
|
|
|
|
|
|
|
|
if inp_len != expected_len {
|
|
|
|
panic!(
|
|
|
|
"expected buffer of size {}, but got {}",
|
|
|
|
expected_len, inp_len
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
marshall_from_haskell_var(inp, inp_len, tag)
|
|
|
|
}
|
|
|
|
}
|