Refactor host

This commit is contained in:
Sergey Pepyakin
2017-12-18 15:18:53 +03:00
parent 848389ed88
commit 0e89639fe6
5 changed files with 83 additions and 77 deletions

View File

@ -4,7 +4,8 @@ use std::env;
use std::fmt;
use std::rc::Rc;
use parity_wasm::elements::Module;
use parity_wasm::interpreter::{Error as InterpreterError, HostModule, HostModuleBuilder,
use parity_wasm::interpreter::{
Error as InterpreterError, HostModule, HostModuleBuilder,
ModuleInstance, UserError};
#[derive(Debug)]
@ -157,16 +158,16 @@ fn env_host_module<'a>() -> HostModule<Runtime<'a>> {
let mut builder = HostModuleBuilder::<Runtime>::new();
builder.with_func1(
"set",
|state: &Runtime, idx: i32| -> Result<Option<()>, InterpreterError> {
|state: &Runtime, idx: i32| -> Result<(), InterpreterError> {
state.game.set(idx, state.player)?;
Ok(None)
Ok(())
},
);
builder.with_func1(
"get",
|state: &Runtime, idx: i32| -> Result<Option<i32>, InterpreterError> {
|state: &Runtime, idx: i32| -> Result<i32, InterpreterError> {
let val: i32 = tictactoe::Player::into_i32(state.game.get(idx).unwrap());
Ok(Some(val))
Ok(val)
},
);
builder.build()

View File

@ -7,7 +7,7 @@ use interpreter::func::FuncInstance;
use interpreter::global::GlobalInstance;
use interpreter::memory::MemoryInstance;
use interpreter::table::TableInstance;
use interpreter::value::RuntimeValue;
use interpreter::value::{RuntimeValue, TryInto};
use interpreter::Error;
use interpreter::ImportResolver;
@ -25,8 +25,8 @@ impl<St> HostModuleBuilder<St> {
}
pub fn with_func0<
Cl: Fn(&St) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static,
Cl: Fn(&St) -> Result<Ret, Error> + 'static,
Ret: IntoReturnVal + 'static,
N: Into<String>,
>(
&mut self,
@ -35,8 +35,8 @@ impl<St> HostModuleBuilder<St> {
) {
let func_type = FunctionType::new(vec![], Ret::value_type());
let host_func = Rc::new(move |state: &St, _args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let result = f(state);
result.map(|r| r.and_then(|r| r.as_return_val()))
let result = f(state)?.into_return_val();
Ok(result)
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -44,8 +44,8 @@ impl<St> HostModuleBuilder<St> {
}
pub fn with_func1<
Cl: Fn(&St, P1) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static,
Cl: Fn(&St, P1) -> Result<Ret, Error> + 'static,
Ret: IntoReturnVal + 'static,
P1: FromArg + 'static,
N: Into<String>,
>(
@ -56,8 +56,8 @@ impl<St> HostModuleBuilder<St> {
let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type());
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let arg0 = P1::from_arg(&args[0]);
let result = f(state, arg0);
result.map(|r| r.and_then(|r| r.as_return_val()))
let result = f(state, arg0)?.into_return_val();
Ok(result)
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -65,8 +65,8 @@ impl<St> HostModuleBuilder<St> {
}
pub fn with_func2<
Cl: Fn(&St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
Ret: AsReturnVal + 'static,
Cl: Fn(&St, P1, P2) -> Result<Ret, Error> + 'static,
Ret: IntoReturnVal + 'static,
P1: FromArg + 'static,
P2: FromArg + 'static,
N: Into<String>,
@ -79,8 +79,8 @@ impl<St> HostModuleBuilder<St> {
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
let p1 = P1::from_arg(&args[0]);
let p2 = P2::from_arg(&args[1]);
let result = f(state, p1, p2);
result.map(|r| r.and_then(|r| r.as_return_val()))
let result = f(state, p1, p2)?.into_return_val();
Ok(result)
});
let func = FuncInstance::alloc_host(Rc::new(func_type), host_func);
@ -177,49 +177,66 @@ impl<St> ImportResolver<St> for HostModule<St> {
}
}
pub trait AnyFunc<St> {
fn call_as_any(
&self,
state: &St,
args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error>;
}
pub trait FromArg {
pub trait FromArg where Self: Sized {
fn from_arg(arg: &RuntimeValue) -> Self;
fn value_type() -> ValueType;
}
impl FromArg for i32 {
macro_rules! impl_from_arg {
($ty: ident, $val_ty: ident) => {
impl FromArg for $ty {
fn from_arg(arg: &RuntimeValue) -> Self {
match arg {
&RuntimeValue::I32(v) => v,
unexpected => panic!("Expected I32, got {:?}", unexpected),
}
arg
.try_into()
.expect(
concat!("Due to validation, arg expected to be ", stringify!($val_ty))
)
}
fn value_type() -> ValueType {
ValueType::I32
use self::ValueType::*;
$val_ty
}
}
}
}
pub trait AsReturnVal {
fn as_return_val(self) -> Option<RuntimeValue>;
impl_from_arg!(i32, I32);
impl_from_arg!(u32, I32);
impl_from_arg!(i64, I64);
impl_from_arg!(u64, I64);
impl_from_arg!(f32, F32);
impl_from_arg!(f64, F64);
pub trait IntoReturnVal {
fn into_return_val(self) -> Option<RuntimeValue>;
fn value_type() -> Option<ValueType>;
}
impl AsReturnVal for i32 {
fn as_return_val(self) -> Option<RuntimeValue> {
macro_rules! impl_into_return_val {
($ty: ident, $val_ty: ident) => {
impl IntoReturnVal for $ty {
fn into_return_val(self) -> Option<RuntimeValue> {
Some(self.into())
}
fn value_type() -> Option<ValueType> {
Some(ValueType::I32)
use self::ValueType::*;
Some($val_ty)
}
}
}
}
impl AsReturnVal for () {
fn as_return_val(self) -> Option<RuntimeValue> {
impl_into_return_val!(i32, I32);
impl_into_return_val!(u32, I32);
impl_into_return_val!(i64, I64);
impl_into_return_val!(u64, I64);
impl_into_return_val!(f32, F32);
impl_into_return_val!(f64, F64);
impl IntoReturnVal for () {
fn into_return_val(self) -> Option<RuntimeValue> {
None
}
@ -227,27 +244,3 @@ impl AsReturnVal for () {
None
}
}
impl<St, Ret: AsReturnVal> AnyFunc<St> for Fn(&St) -> Result<Option<Ret>, Error> {
fn call_as_any(
&self,
state: &St,
_args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> {
let result = self(state);
result.map(|r| r.and_then(|r| r.as_return_val()))
}
}
impl<St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> AnyFunc<St> for Fn(&St, P1, P2) -> Result<Option<Ret>, Error> {
fn call_as_any(
&self,
state: &St,
args: &[RuntimeValue],
) -> Result<Option<RuntimeValue>, Error> {
let p1 = P1::from_arg(&args[0]);
let p2 = P2::from_arg(&args[1]);
let result = self(state, p1, p2);
result.map(|r| r.and_then(|r| r.as_return_val()))
}
}

View File

@ -151,7 +151,7 @@ pub use self::memory::MemoryInstance;
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue;
pub use self::host::{HostModule, HostModuleBuilder, HostFunc, AsReturnVal, FromArg};
pub use self::host::{HostModule, HostModuleBuilder, HostFunc, IntoReturnVal, FromArg};
pub use self::imports::{ImportResolver, Imports};
pub use self::module::ModuleInstance;
pub use self::global::GlobalInstance;

View File

@ -133,7 +133,7 @@ fn build_env_module() -> HostModule<TestState> {
let sum = memory_value + fn_argument;
state.memory.set(0, &vec![sum]).unwrap();
state.values.borrow_mut().push(sum as i32);
Ok(Some(sum as i32))
Ok(sum as i32)
});
builder.with_func2("sub", |state: &TestState, arg: i32, unused: i32| {
let memory_value = state.memory.get(0, 1).unwrap()[0];
@ -144,9 +144,9 @@ fn build_env_module() -> HostModule<TestState> {
let diff = memory_value - fn_argument;
state.memory.set(0, &vec![diff]).unwrap();
state.values.borrow_mut().push(diff as i32);
Ok(Some(diff as i32))
Ok(diff as i32)
});
builder.with_func2("err", |_: &TestState, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
builder.with_func2("err", |_: &TestState, _unused1: i32, _unused2: i32| -> Result<i32, Error> {
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
});
builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap()));
@ -323,14 +323,14 @@ fn native_ref_state() {
let mut host_module_builder = HostModuleBuilder::<HostState>::new();
host_module_builder.with_func1(
"inc",
|state: &HostState, val: i32| -> Result<Option<()>, Error> {
|state: &HostState, val: i32| -> Result<(), Error> {
let mut ext_state = state.ext_state.borrow_mut();
// TODO: fix this
fn inc(acc: &mut i32, val: i32) {
*acc += val;
}
inc(&mut *ext_state, val);
Ok(None)
Ok(())
},
);
host_module_builder.build()

View File

@ -153,6 +153,18 @@ impl From<i64> for RuntimeValue {
}
}
impl From<u32> for RuntimeValue {
fn from(val: u32) -> Self {
RuntimeValue::I32(val as i32)
}
}
impl From<u64> for RuntimeValue {
fn from(val: u64) -> Self {
RuntimeValue::I64(val as i64)
}
}
impl From<f32> for RuntimeValue {
fn from(val: f32) -> Self {
RuntimeValue::F32(val)