use crate::{RIType, util::{unpack_ptr_and_len, pack_ptr_and_len}};
#[cfg(feature = "std")]
use crate::host::*;
#[cfg(not(feature = "std"))]
use crate::wasm::*;
#[cfg(feature = "std")]
use tetcore_wasm_interface::{FunctionContext, Pointer, Result};
use tetcore_std::{marker::PhantomData, convert::TryFrom};
#[cfg(not(feature = "std"))]
use tetcore_std::vec::Vec;
pub use tp_runtime_interface_proc_macro::PassByCodec;
pub use tp_runtime_interface_proc_macro::PassByInner;
pub use tp_runtime_interface_proc_macro::PassByEnum;
pub trait PassBy: Sized {
type PassBy: PassByImpl<Self>;
}
#[cfg(feature = "std")]
pub trait PassByImpl<T>: RIType {
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType>;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T>;
}
#[cfg(not(feature = "std"))]
pub trait PassByImpl<T>: RIType {
type Owned;
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned>;
fn from_ffi_value(arg: Self::FFIType) -> T;
}
impl<T: PassBy> RIType for T {
type FFIType = <T::PassBy as RIType>::FFIType;
}
#[cfg(feature = "std")]
impl<T: PassBy> IntoFFIValue for T {
fn into_ffi_value(
self,
context: &mut dyn FunctionContext,
) -> Result<<T::PassBy as RIType>::FFIType> {
T::PassBy::into_ffi_value(self, context)
}
}
#[cfg(feature = "std")]
impl<T: PassBy> FromFFIValue for T {
type SelfInstance = Self;
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: <T::PassBy as RIType>::FFIType,
) -> Result<Self> {
T::PassBy::from_ffi_value(context, arg)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassBy> IntoFFIValue for T {
type Owned = <T::PassBy as PassByImpl<T>>::Owned;
fn into_ffi_value(&self) -> WrappedFFIValue<<T::PassBy as RIType>::FFIType, Self::Owned> {
T::PassBy::into_ffi_value(self)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassBy> FromFFIValue for T {
fn from_ffi_value(arg: <T::PassBy as RIType>::FFIType) -> Self {
T::PassBy::from_ffi_value(arg)
}
}
pub struct Codec<T: codec::Codec>(PhantomData<T>);
#[cfg(feature = "std")]
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
let vec = instance.encode();
let ptr = context.allocate_memory(vec.len() as u32)?;
context.write_memory(ptr, &vec)?;
Ok(pack_ptr_and_len(ptr.into(), vec.len() as u32))
}
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
let (ptr, len) = unpack_ptr_and_len(arg);
let vec = context.read_memory(Pointer::new(ptr), len)?;
T::decode(&mut &vec[..])
.map_err(|e| format!("Could not decode value from wasm: {}", e))
}
}
#[cfg(not(feature = "std"))]
impl<T: codec::Codec> PassByImpl<T> for Codec<T> {
type Owned = Vec<u8>;
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
let data = instance.encode();
let ffi_value = pack_ptr_and_len(data.as_ptr() as u32, data.len() as u32);
(ffi_value, data).into()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
let (ptr, len) = unpack_ptr_and_len(arg);
let len = len as usize;
let encoded = if len == 0 {
Vec::new()
} else {
unsafe { Vec::from_raw_parts(ptr as *mut u8, len, len) }
};
T::decode(&mut &encoded[..]).expect("Host to wasm values are encoded correctly; qed")
}
}
impl<T: codec::Codec> RIType for Codec<T> {
type FFIType = u64;
}
pub trait PassByInner: Sized {
type Inner: RIType;
fn into_inner(self) -> Self::Inner;
fn inner(&self) -> &Self::Inner;
fn from_inner(inner: Self::Inner) -> Self;
}
pub struct Inner<T: PassByInner<Inner = I>, I: RIType>(PhantomData<(T, I)>);
#[cfg(feature = "std")]
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
where I: IntoFFIValue + FromFFIValue<SelfInstance=I>
{
fn into_ffi_value(
instance: T,
context: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
instance.into_inner().into_ffi_value(context)
}
fn from_ffi_value(
context: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
I::from_ffi_value(context, arg).map(T::from_inner)
}
}
#[cfg(not(feature = "std"))]
impl<T: PassByInner<Inner = I>, I: RIType> PassByImpl<T> for Inner<T, I>
where I: IntoFFIValue + FromFFIValue
{
type Owned = I::Owned;
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
instance.inner().into_ffi_value()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
T::from_inner(I::from_ffi_value(arg))
}
}
impl<T: PassByInner<Inner = I>, I: RIType> RIType for Inner<T, I> {
type FFIType = I::FFIType;
}
pub struct Enum<T: Copy + Into<u8> + TryFrom<u8>>(PhantomData<T>);
#[cfg(feature = "std")]
impl<T: Copy + Into<u8> + TryFrom<u8>> PassByImpl<T> for Enum<T> {
fn into_ffi_value(
instance: T,
_: &mut dyn FunctionContext,
) -> Result<Self::FFIType> {
Ok(instance.into())
}
fn from_ffi_value(
_: &mut dyn FunctionContext,
arg: Self::FFIType,
) -> Result<T> {
T::try_from(arg).map_err(|_| format!("Invalid enum discriminant: {}", arg))
}
}
#[cfg(not(feature = "std"))]
impl<T: Copy + Into<u8> + TryFrom<u8, Error = ()>> PassByImpl<T> for Enum<T> {
type Owned = ();
fn into_ffi_value(instance: &T) -> WrappedFFIValue<Self::FFIType, Self::Owned> {
let value: u8 = (*instance).into();
value.into()
}
fn from_ffi_value(arg: Self::FFIType) -> T {
T::try_from(arg).expect("Host to wasm provides a valid enum discriminant; qed")
}
}
impl<T: Copy + Into<u8> + TryFrom<u8>> RIType for Enum<T> {
type FFIType = u8;
}