use soroban_env_macros::generate_call_macro_with_all_host_functions;
use crate::Object;
use super::Symbol;
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::xdr::{ScErrorCode, ScErrorType};
pub trait EnvBase: Sized + Clone {
type Error: core::fmt::Debug + Into<crate::Error>;
fn check_val_integrity(&self, val: Val) -> Result<(), Self::Error> {
if !val.is_good() {
return Err(self.error_from_error_val(Error::from_type_and_code(
ScErrorType::Value,
ScErrorCode::InvalidInput,
)));
}
if let Ok(obj) = Object::try_from(val) {
self.check_obj_integrity(obj)
} else {
Ok(())
}
}
fn check_obj_integrity(&self, _obj: Object) -> Result<(), Self::Error> {
Ok(())
}
fn error_from_error_val(&self, e: crate::Error) -> Self::Error;
#[cfg(feature = "testutils")]
fn escalate_error_to_panic(&self, e: Self::Error) -> !;
#[cfg(all(feature = "std", feature = "testutils"))]
#[deprecated(note = "replaced by trace_env_call")]
fn env_call_hook(&self, _fname: &'static str, _args: &[String]) -> Result<(), Self::Error> {
Ok(())
}
#[cfg(all(feature = "std", feature = "testutils"))]
#[deprecated(note = "replaced by trace_env_ret")]
fn env_ret_hook(
&self,
_fname: &'static str,
_res: &Result<String, &Self::Error>,
) -> Result<(), Self::Error> {
Ok(())
}
#[cfg(feature = "std")]
fn tracing_enabled(&self) -> bool {
false
}
#[cfg(feature = "std")]
fn trace_env_call(
&self,
_fname: &'static str,
_args: &[&dyn core::fmt::Debug],
) -> Result<(), Self::Error> {
Ok(())
}
#[cfg(feature = "std")]
fn trace_env_ret(
&self,
_fname: &'static str,
_res: &Result<&dyn core::fmt::Debug, &Self::Error>,
) -> Result<(), Self::Error> {
Ok(())
}
fn augment_err_result<T>(&self, x: Result<T, Self::Error>) -> Result<T, Self::Error> {
x
}
fn bytes_copy_from_slice(
&self,
b: BytesObject,
b_pos: U32Val,
slice: &[u8],
) -> Result<BytesObject, Self::Error>;
fn bytes_copy_to_slice(
&self,
b: BytesObject,
b_pos: U32Val,
slice: &mut [u8],
) -> Result<(), Self::Error>;
fn string_copy_to_slice(
&self,
b: StringObject,
b_pos: U32Val,
slice: &mut [u8],
) -> Result<(), Self::Error>;
fn symbol_copy_to_slice(
&self,
b: SymbolObject,
b_pos: U32Val,
mem: &mut [u8],
) -> Result<(), Self::Error>;
fn bytes_new_from_slice(&self, slice: &[u8]) -> Result<BytesObject, Self::Error>;
fn string_new_from_slice(&self, slice: &[u8]) -> Result<StringObject, Self::Error>;
fn symbol_new_from_slice(&self, slice: &[u8]) -> Result<SymbolObject, Self::Error>;
fn map_new_from_slices(&self, keys: &[&str], vals: &[Val]) -> Result<MapObject, Self::Error>;
fn map_unpack_to_slice(
&self,
map: MapObject,
keys: &[&str],
vals: &mut [Val],
) -> Result<Void, Self::Error>;
fn vec_new_from_slice(&self, vals: &[Val]) -> Result<VecObject, Self::Error>;
fn vec_unpack_to_slice(&self, vec: VecObject, vals: &mut [Val]) -> Result<Void, Self::Error>;
fn symbol_index_in_strs(&self, key: Symbol, strs: &[&str]) -> Result<U32Val, Self::Error>;
fn log_from_slice(&self, msg: &str, vals: &[Val]) -> Result<Void, Self::Error>;
fn check_protocol_version_lower_bound(&self, lower_bound: u32) -> Result<(), Self::Error>;
fn check_protocol_version_upper_bound(&self, upper_bound: u32) -> Result<(), Self::Error>;
}
pub trait CheckedEnvArg: Sized {
fn check_env_arg<E: crate::Env>(self, _e: &E) -> Result<Self, E::Error> {
Ok(self)
}
}
impl CheckedEnvArg for i64 {}
impl CheckedEnvArg for u64 {}
impl CheckedEnvArg for StorageType {}
macro_rules! impl_checkedenvarg_for_val_or_wrapper {
($type:ty) => {
impl CheckedEnvArg for $type {
fn check_env_arg<E: crate::Env>(self, e: &E) -> Result<Self, E::Error> {
e.check_val_integrity(Val::from(self.clone()))?;
Ok(self)
}
}
};
}
impl_checkedenvarg_for_val_or_wrapper!(Val);
impl_checkedenvarg_for_val_or_wrapper!(Symbol);
impl_checkedenvarg_for_val_or_wrapper!(AddressObject);
impl_checkedenvarg_for_val_or_wrapper!(MuxedAddressObject);
impl_checkedenvarg_for_val_or_wrapper!(BytesObject);
impl_checkedenvarg_for_val_or_wrapper!(DurationObject);
impl_checkedenvarg_for_val_or_wrapper!(TimepointObject);
impl_checkedenvarg_for_val_or_wrapper!(SymbolObject);
impl_checkedenvarg_for_val_or_wrapper!(StringObject);
impl_checkedenvarg_for_val_or_wrapper!(VecObject);
impl_checkedenvarg_for_val_or_wrapper!(MapObject);
impl_checkedenvarg_for_val_or_wrapper!(I64Object);
impl_checkedenvarg_for_val_or_wrapper!(I128Object);
impl_checkedenvarg_for_val_or_wrapper!(I256Object);
impl_checkedenvarg_for_val_or_wrapper!(U64Object);
impl_checkedenvarg_for_val_or_wrapper!(U128Object);
impl_checkedenvarg_for_val_or_wrapper!(U256Object);
impl_checkedenvarg_for_val_or_wrapper!(U64Val);
impl_checkedenvarg_for_val_or_wrapper!(U256Val);
impl_checkedenvarg_for_val_or_wrapper!(I256Val);
impl_checkedenvarg_for_val_or_wrapper!(Void);
impl_checkedenvarg_for_val_or_wrapper!(Bool);
impl_checkedenvarg_for_val_or_wrapper!(Error);
impl_checkedenvarg_for_val_or_wrapper!(U32Val);
generate_call_macro_with_all_host_functions!("env.json");
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, $($arg:$type),*) -> Result<$ret, Self::Error>;
};
}
macro_rules! generate_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 Env: EnvBase
{
$(
$(
host_function_helper!{$($min_proto)?, $($max_proto)?, $(#[$fn_attr])* fn $fn_id $args -> $ret}
)*
)*
}
};
}
call_macro_with_all_host_functions! { generate_env_trait }