#![allow(clippy::needless_lifetimes)]
#[cfg(feature = "wasmi")]
use crate::xdr::{ScErrorCode, ScErrorType};
use super::{
AddressObject, Bool, BytesObject, DurationObject, Error, I128Object, I256Object, I256Val,
I64Object, MapObject, MuxedAddressObject, StorageType, StringObject, SymbolObject,
TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject,
Void,
};
use crate::call_macro_with_all_host_functions;
use crate::{CheckedEnvArg, EnvBase, Symbol};
#[cfg(not(feature = "wasmi"))]
use core::marker::PhantomData;
#[cfg(feature = "wasmi")]
pub struct VmCaller<'a, T>(pub Option<wasmi::Caller<'a, T>>);
#[cfg(feature = "wasmi")]
impl<'a, T> VmCaller<'a, T> {
pub fn none() -> Self {
VmCaller(None)
}
pub fn try_ref(&self) -> Result<&wasmi::Caller<'a, T>, Error> {
match &self.0 {
Some(caller) => Ok(caller),
None => Err(Error::from_type_and_code(
ScErrorType::Context,
ScErrorCode::InternalError,
)),
}
}
pub fn try_mut(&mut self) -> Result<&mut wasmi::Caller<'a, T>, Error> {
match &mut self.0 {
Some(caller) => Ok(caller),
None => Err(Error::from_type_and_code(
ScErrorType::Context,
ScErrorCode::InternalError,
)),
}
}
}
#[cfg(not(feature = "wasmi"))]
pub struct VmCaller<'a, T> {
_nothing: PhantomData<&'a T>,
}
#[cfg(not(feature = "wasmi"))]
impl<'a, T> VmCaller<'a, T> {
pub fn none() -> Self {
VmCaller {
_nothing: PhantomData,
}
}
}
macro_rules! host_function_helper {
{
$($min_proto:literal)?, $($max_proto:literal)?,
$(#[$attr:meta])*
fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty
}
=>
{
$(#[$attr])*
fn $fn_id(&self, vmcaller: &mut VmCaller<Self::VmUserState>, $($arg:$type),*) -> Result<$ret, Self::Error>;
};
}
macro_rules! generate_vmcaller_checked_env_trait {
{
$(
// This outer pattern matches a single 'mod' block of the token-tree
// passed from the x-macro to this macro. It is embedded in a `$()*`
// pattern-repetition matcher so that it will match all provided
// 'mod' blocks provided.
$(#[$mod_attr:meta])*
mod $mod_id:ident $mod_str:literal
{
$(
// This inner pattern matches a single function description
// inside a 'mod' block in the token-tree passed from the
// x-macro to this macro. It is embedded in a `$()*`
// pattern-repetition matcher so that it will match all such
// descriptions.
$(#[$fn_attr:meta])*
{ $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty }
)*
}
)*
}
=>
{
pub trait VmCallerEnv: EnvBase
{
type VmUserState;
$(
$(
host_function_helper!{$($min_proto)?, $($max_proto)?, $(#[$fn_attr])* fn $fn_id $args -> $ret}
)*
)*
}
};
}
call_macro_with_all_host_functions! { generate_vmcaller_checked_env_trait }
macro_rules! vmcaller_none_function_helper {
{$($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident($($arg:ident:$type:ty),*) -> $ret:ty}
=>
{
fn $fn_id(&self, $($arg:$type),*) -> Result<$ret, Self::Error> {
$( self.check_protocol_version_lower_bound($min_proto)?; )?
$( self.check_protocol_version_upper_bound($max_proto)?; )?
#[cfg(all(not(target_family = "wasm"), feature = "tracy"))]
let _span = tracy_span!(core::stringify!($fn_id));
#[cfg(feature = "std")]
if self.tracing_enabled()
{
self.trace_env_call(&core::stringify!($fn_id), &[$(&$arg),*])?;
}
let res: Result<_, _> = self.augment_err_result(<Self as VmCallerEnv>::$fn_id(self, &mut VmCaller::none(), $($arg.check_env_arg(self)?),*));
let res = match res {
Ok(ok) => Ok(ok.check_env_arg(self)?),
Err(err) => Err(err)
};
#[cfg(feature = "std")]
if self.tracing_enabled()
{
let dyn_res: Result<&dyn core::fmt::Debug,&Self::Error> = match &res {
Ok(ref ok) => Ok(ok),
Err(err) => Err(err)
};
self.trace_env_ret(&core::stringify!($fn_id), &dyn_res)?;
}
res
}
};
}
macro_rules! impl_env_for_vmcaller_env {
{
$(
// This outer pattern matches a single 'mod' block of the token-tree
// passed from the x-macro to this macro. It is embedded in a `$()*`
// pattern-repetition matcher so that it will match all provided
// 'mod' blocks provided.
$(#[$mod_attr:meta])*
mod $mod_id:ident $mod_str:literal
{
$(
// This inner pattern matches a single function description
// inside a 'mod' block in the token-tree passed from the
// x-macro to this macro. It is embedded in a `$()*`
// pattern-repetition matcher so that it will match all such
// descriptions.
$(#[$fn_attr:meta])*
{ $fn_str:literal, $($min_proto:literal)?, $($max_proto:literal)?, fn $fn_id:ident $args:tt -> $ret:ty }
)*
}
)*
}
=>
{
impl<T:VmCallerEnv> $crate::Env for T
{
$(
$(
vmcaller_none_function_helper!{$($min_proto)?, $($max_proto)?, fn $fn_id $args -> $ret}
)*
)*
}
};
}
call_macro_with_all_host_functions! { impl_env_for_vmcaller_env }