Merge pull request #6 from pepyakin/args-wrapper
Safe/utility arguments wrapper
This commit is contained in:
commit
88c25b6361
|
@ -6,8 +6,9 @@ use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use wasmi::{
|
use wasmi::{
|
||||||
Error as InterpreterError, ModuleInstance, ModuleRef,
|
Error as InterpreterError, ModuleInstance, ModuleRef,
|
||||||
Externals, RuntimeValue, FuncRef, TryInto, ModuleImportResolver,
|
Externals, RuntimeValue, FuncRef, ModuleImportResolver,
|
||||||
FuncInstance, HostError, ImportsBuilder, Signature, ValueType,
|
FuncInstance, HostError, ImportsBuilder, Signature, ValueType,
|
||||||
|
RuntimeArgs,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -147,16 +148,16 @@ impl<'a> Externals for Runtime<'a> {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: &[RuntimeValue],
|
args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||||
match index {
|
match index {
|
||||||
SET_FUNC_INDEX => {
|
SET_FUNC_INDEX => {
|
||||||
let idx: i32 = args[0].try_into().unwrap();
|
let idx: i32 = args.nth(0)?;
|
||||||
self.game.set(idx, self.player)?;
|
self.game.set(idx, self.player)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
GET_FUNC_INDEX => {
|
GET_FUNC_INDEX => {
|
||||||
let idx: i32 = args[0].try_into().unwrap();
|
let idx: i32 = args.nth(0)?;
|
||||||
let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?);
|
let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?);
|
||||||
Ok(Some(val.into()))
|
Ok(Some(val.into()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ use wasmi::{
|
||||||
GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder,
|
GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder,
|
||||||
MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance,
|
MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance,
|
||||||
ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType,
|
ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType,
|
||||||
load_from_buffer, LoadedModule, Signature, MemoryDescriptor,
|
load_from_buffer, LoadedModule, Signature, MemoryDescriptor,
|
||||||
TableDescriptor, GlobalDescriptor, FuncInstance,
|
TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -57,7 +57,7 @@ impl Externals for SpecModule {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: &[RuntimeValue],
|
args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||||
match index {
|
match index {
|
||||||
PRINT_FUNC_INDEX => {
|
PRINT_FUNC_INDEX => {
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl fmt::Debug for FuncInstance {
|
||||||
ref signature,
|
ref signature,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// We can't write description of self.module here, because it generate
|
// We can't write description of self.module here, because it generate
|
||||||
// debug string for function instances and this will lead to infinite loop.
|
// debug string for function instances and this will lead to infinite loop.
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
@ -132,7 +132,7 @@ impl FuncInstance {
|
||||||
let mut interpreter = Interpreter::new(externals);
|
let mut interpreter = Interpreter::new(externals);
|
||||||
interpreter.run_function(ctx)
|
interpreter.run_function(ctx)
|
||||||
}
|
}
|
||||||
InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args),
|
InvokeKind::Host(host_func, args) => externals.invoke_index(host_func, args.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
57
src/host.rs
57
src/host.rs
|
@ -1,7 +1,38 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use value::RuntimeValue;
|
use value::{RuntimeValue, TryInto};
|
||||||
use Error;
|
use Error;
|
||||||
|
|
||||||
|
/// Safe wrapper for list of arguments
|
||||||
|
#[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<'a> RuntimeArgs<'a> {
|
||||||
|
|
||||||
|
/// Extract argument by index `idx` returning error if cast is invalid or not enough arguments
|
||||||
|
pub fn nth<T>(&self, idx: usize) -> Result<T, Error> where RuntimeValue: TryInto<T, Error> {
|
||||||
|
Ok(self.nth_value(idx)?.try_into().map_err(|_| Error::Value("Invalid argument cast".to_owned()))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract argument as a runtime value by index `idx` returning error is not enough arguments
|
||||||
|
pub fn nth_value(&self, idx: usize) -> Result<RuntimeValue, Error> {
|
||||||
|
if self.0.len() <= idx {
|
||||||
|
return Err(Error::Value("Invalid argument index".to_owned()));
|
||||||
|
}
|
||||||
|
Ok(self.0[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Total number of arguments
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Custom user error.
|
/// Custom user error.
|
||||||
pub trait HostError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
|
pub trait HostError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -35,7 +66,7 @@ pub trait Externals {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: &[RuntimeValue],
|
args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error>;
|
) -> Result<Option<RuntimeValue>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,8 +76,28 @@ impl Externals for NopExternals {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
_index: usize,
|
_index: usize,
|
||||||
_args: &[RuntimeValue],
|
_args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
Err(Error::Trap("invoke index on no-op externals".into()))
|
Err(Error::Trap("invoke index on no-op externals".into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use value::RuntimeValue;
|
||||||
|
use super::RuntimeArgs;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn i32_runtime_args() {
|
||||||
|
let args: RuntimeArgs = (&[RuntimeValue::I32(0)][..]).into();
|
||||||
|
let val: i32 = args.nth(0).unwrap();
|
||||||
|
assert_eq!(val, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn i64_invalid_arg_cast() {
|
||||||
|
let args: RuntimeArgs = (&[RuntimeValue::I64(90534534545322)][..]).into();
|
||||||
|
assert!(args.nth::<i32>(0).is_err());
|
||||||
|
}
|
||||||
|
}
|
|
@ -130,7 +130,7 @@ mod tests;
|
||||||
pub use self::memory::{MemoryInstance, MemoryRef};
|
pub use self::memory::{MemoryInstance, MemoryRef};
|
||||||
pub use self::table::{TableInstance, TableRef};
|
pub use self::table::{TableInstance, TableRef};
|
||||||
pub use self::value::{RuntimeValue, TryInto};
|
pub use self::value::{RuntimeValue, TryInto};
|
||||||
pub use self::host::{Externals, NopExternals, HostError};
|
pub use self::host::{Externals, NopExternals, HostError, RuntimeArgs};
|
||||||
pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder};
|
pub use self::imports::{ModuleImportResolver, ImportResolver, ImportsBuilder};
|
||||||
pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef};
|
pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef};
|
||||||
pub use self::global::{GlobalInstance, GlobalRef};
|
pub use self::global::{GlobalInstance, GlobalRef};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
|
Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
|
||||||
MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef,
|
MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef,
|
||||||
RuntimeValue, TryInto, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor,
|
RuntimeValue, RuntimeArgs, LoadedModule, load_from_buffer, TableDescriptor, MemoryDescriptor,
|
||||||
};
|
};
|
||||||
use types::ValueType;
|
use types::ValueType;
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
|
@ -78,25 +78,24 @@ impl Externals for TestHost {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: &[RuntimeValue],
|
args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let mut args = args.iter().cloned();
|
|
||||||
match index {
|
match index {
|
||||||
SUB_FUNC_INDEX => {
|
SUB_FUNC_INDEX => {
|
||||||
let a: i32 = args.next().unwrap().try_into().unwrap();
|
let a: i32 = args.nth(0)?;
|
||||||
let b: i32 = args.next().unwrap().try_into().unwrap();
|
let b: i32 = args.nth(1)?;
|
||||||
|
|
||||||
let result: RuntimeValue = (a - b).into();
|
let result: RuntimeValue = (a - b).into();
|
||||||
|
|
||||||
Ok(Some(result))
|
Ok(Some(result))
|
||||||
}
|
}
|
||||||
ERR_FUNC_INDEX => {
|
ERR_FUNC_INDEX => {
|
||||||
let error_code: u32 = args.next().unwrap().try_into().unwrap();
|
let error_code = args.nth::<i32>(0)? as u32;
|
||||||
let error = HostErrorWithCode { error_code };
|
let error = HostErrorWithCode { error_code };
|
||||||
Err(Error::Host(Box::new(error)))
|
Err(Error::Host(Box::new(error)))
|
||||||
}
|
}
|
||||||
INC_MEM_FUNC_INDEX => {
|
INC_MEM_FUNC_INDEX => {
|
||||||
let ptr: u32 = args.next().unwrap().try_into().unwrap();
|
let ptr = args.nth::<i32>(0)? as u32;
|
||||||
|
|
||||||
let memory = self.memory.as_ref().expect(
|
let memory = self.memory.as_ref().expect(
|
||||||
"Function 'inc_mem' expects attached memory",
|
"Function 'inc_mem' expects attached memory",
|
||||||
|
@ -109,7 +108,7 @@ impl Externals for TestHost {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
GET_MEM_FUNC_INDEX => {
|
GET_MEM_FUNC_INDEX => {
|
||||||
let ptr: u32 = args.next().unwrap().try_into().unwrap();
|
let ptr = args.nth::<i32>(0)? as u32;
|
||||||
|
|
||||||
let memory = self.memory.as_ref().expect(
|
let memory = self.memory.as_ref().expect(
|
||||||
"Function 'get_mem' expects attached memory",
|
"Function 'get_mem' expects attached memory",
|
||||||
|
@ -120,7 +119,7 @@ impl Externals for TestHost {
|
||||||
Ok(Some(RuntimeValue::I32(buf[0] as i32)))
|
Ok(Some(RuntimeValue::I32(buf[0] as i32)))
|
||||||
}
|
}
|
||||||
RECURSE_FUNC_INDEX => {
|
RECURSE_FUNC_INDEX => {
|
||||||
let val: RuntimeValue = args.next().unwrap();
|
let val = args.nth_value(0)?;
|
||||||
|
|
||||||
let instance = self.instance
|
let instance = self.instance
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -463,12 +462,11 @@ fn defer_providing_externals() {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
args: &[RuntimeValue],
|
args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
match index {
|
match index {
|
||||||
INC_FUNC_INDEX => {
|
INC_FUNC_INDEX => {
|
||||||
let mut args = args.iter().cloned();
|
let a = args.nth::<i32>(0)? as u32;
|
||||||
let a: u32 = args.next().unwrap().try_into().unwrap();
|
|
||||||
*self.acc += a;
|
*self.acc += a;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -528,7 +526,7 @@ fn two_envs_one_externals() {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
_args: &[RuntimeValue],
|
_args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
match index {
|
match index {
|
||||||
PRIVILEGED_FUNC_INDEX => {
|
PRIVILEGED_FUNC_INDEX => {
|
||||||
|
@ -648,7 +646,7 @@ fn dynamically_add_host_func() {
|
||||||
fn invoke_index(
|
fn invoke_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
_args: &[RuntimeValue],
|
_args: RuntimeArgs,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
match index {
|
match index {
|
||||||
ADD_FUNC_FUNC_INDEX => {
|
ADD_FUNC_FUNC_INDEX => {
|
||||||
|
|
Loading…
Reference in New Issue