use crate::{value::FromValue, RuntimeValue, Trap, TrapCode};
#[derive(Debug)]
pub struct RuntimeArgs<'a>(&'a [RuntimeValue]);
impl<'a> From<&'a [RuntimeValue]> for RuntimeArgs<'a> {
fn from(inner: &'a [RuntimeValue]) -> Self {
RuntimeArgs(inner)
}
}
impl AsRef<[RuntimeValue]> for RuntimeArgs<'_> {
fn as_ref(&self) -> &[RuntimeValue] {
self.0
}
}
impl RuntimeArgs<'_> {
pub fn nth_checked<T>(&self, idx: usize) -> Result<T, Trap>
where
T: FromValue,
{
self.nth_value_checked(idx)?
.try_into()
.ok_or(TrapCode::UnexpectedSignature)
.map_err(Into::into)
}
pub fn nth_value_checked(&self, idx: usize) -> Result<RuntimeValue, Trap> {
if self.0.len() <= idx {
return Err(TrapCode::UnexpectedSignature.into());
}
Ok(self.0[idx])
}
pub fn nth<T>(&self, idx: usize) -> T
where
T: FromValue,
{
let value = self.nth_value_checked(idx).expect("Invalid argument index");
value.try_into().expect("Unexpected argument type")
}
pub fn len(&self) -> usize {
self.0.len()
}
}
pub trait Externals {
fn invoke_index(
&mut self,
index: usize,
args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Trap>;
}
pub struct NopExternals;
impl Externals for NopExternals {
fn invoke_index(
&mut self,
_index: usize,
_args: RuntimeArgs,
) -> Result<Option<RuntimeValue>, Trap> {
Err(TrapCode::Unreachable.into())
}
}
#[cfg(test)]
mod tests {
use super::RuntimeArgs;
use crate::RuntimeValue;
use casper_wasmi_core::HostError;
#[test]
fn i32_runtime_args() {
let args: RuntimeArgs = (&[RuntimeValue::I32(0)][..]).into();
let val: i32 = args.nth_checked(0).unwrap();
assert_eq!(val, 0);
}
#[test]
fn i64_invalid_arg_cast() {
let args: RuntimeArgs = (&[RuntimeValue::I64(90534534545322)][..]).into();
assert!(args.nth_checked::<i32>(0).is_err());
}
fn _host_error_is_object_safe(_: &dyn HostError) {}
}