mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-15 07:51:46 +00:00
Use shared ref to pass the State.
This commit is contained in:
235
examples/tictactoe.rs
Normal file
235
examples/tictactoe.rs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
extern crate parity_wasm;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fmt;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use parity_wasm::elements::Module;
|
||||||
|
use parity_wasm::interpreter::{Error as InterpreterError, HostModule, HostModuleBuilder,
|
||||||
|
ModuleInstance, UserError};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
OutOfRange,
|
||||||
|
AlreadyOccupied,
|
||||||
|
Interpreter(InterpreterError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<InterpreterError> for Error {
|
||||||
|
fn from(e: InterpreterError) -> Self {
|
||||||
|
Error::Interpreter(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserError for Error {}
|
||||||
|
|
||||||
|
mod tictactoe {
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use super::Error;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Player {
|
||||||
|
X,
|
||||||
|
O,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum GameResult {
|
||||||
|
Draw,
|
||||||
|
Won(Player),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
pub fn into_i32(maybe_player: Option<Player>) -> i32 {
|
||||||
|
match maybe_player {
|
||||||
|
None => 0,
|
||||||
|
Some(Player::X) => 1,
|
||||||
|
Some(Player::O) => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Game {
|
||||||
|
board: RefCell<[Option<Player>; 9]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn new() -> Game {
|
||||||
|
Game {
|
||||||
|
board: RefCell::new([None; 9]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&self, idx: i32, player: Player) -> Result<(), Error> {
|
||||||
|
let mut board = self.board.borrow_mut();
|
||||||
|
if idx < 0 || idx > 9 {
|
||||||
|
return Err(Error::OutOfRange);
|
||||||
|
}
|
||||||
|
if board[idx as usize] != None {
|
||||||
|
return Err(Error::AlreadyOccupied);
|
||||||
|
}
|
||||||
|
board[idx as usize] = Some(player);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, idx: i32) -> Result<Option<Player>, Error> {
|
||||||
|
if idx < 0 || idx > 9 {
|
||||||
|
return Err(Error::OutOfRange);
|
||||||
|
}
|
||||||
|
Ok(self.board.borrow()[idx as usize])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn game_result(&self) -> Option<GameResult> {
|
||||||
|
let board = self.board.borrow();
|
||||||
|
|
||||||
|
// 0, 1, 2
|
||||||
|
// 3, 4, 5
|
||||||
|
// 6, 7, 8
|
||||||
|
let patterns = &[
|
||||||
|
// Rows
|
||||||
|
(0, 1, 2),
|
||||||
|
(3, 4, 5),
|
||||||
|
(6, 7, 8),
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
(0, 3, 6),
|
||||||
|
(1, 4, 7),
|
||||||
|
(2, 5, 8),
|
||||||
|
|
||||||
|
// Diagonals
|
||||||
|
(0, 4, 8),
|
||||||
|
(2, 4, 6),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Returns Some(player) if all cells contain same Player.
|
||||||
|
let all_same = |i1: usize, i2: usize, i3: usize| -> Option<Player> {
|
||||||
|
if board[i1].is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if board[i1] == board[i2] && board[i2] == board[i3] {
|
||||||
|
return board[i1];
|
||||||
|
}
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
for &(i1, i2, i3) in patterns {
|
||||||
|
if let Some(player) = all_same(i1, i2, i3) {
|
||||||
|
return Some(GameResult::Won(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, there is no winner. Check if it's draw.
|
||||||
|
let all_occupied = board.iter().all(|&cell| cell.is_some());
|
||||||
|
if all_occupied {
|
||||||
|
Some(GameResult::Draw)
|
||||||
|
} else {
|
||||||
|
// Nah, there are still empty cells left.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Runtime<'a> {
|
||||||
|
player: tictactoe::Player,
|
||||||
|
game: &'a tictactoe::Game,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate<'a, 'b>(
|
||||||
|
module: &Module,
|
||||||
|
env: &HostModule<Runtime<'a>>,
|
||||||
|
runtime: &'b Runtime<'a>,
|
||||||
|
) -> Result<Rc<ModuleInstance<Runtime<'a>>>, Error> {
|
||||||
|
let instance = ModuleInstance::instantiate(module)
|
||||||
|
.with_import("env", &*env)
|
||||||
|
.run_start(runtime)?;
|
||||||
|
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.game.set(idx, state.player)?;
|
||||||
|
Ok(None)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
builder.with_func1(
|
||||||
|
"get",
|
||||||
|
|state: &Runtime, idx: i32| -> Result<Option<i32>, InterpreterError> {
|
||||||
|
let val: i32 = tictactoe::Player::into_i32(state.game.get(idx).unwrap());
|
||||||
|
Ok(Some(val))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play<'a>(
|
||||||
|
x_module: &Module,
|
||||||
|
o_module: &Module,
|
||||||
|
host_module: &HostModule<Runtime<'a>>,
|
||||||
|
game: &'a tictactoe::Game,
|
||||||
|
) -> Result<tictactoe::GameResult, Error> {
|
||||||
|
// Instantiate modules of X and O players.
|
||||||
|
let x_instance = {
|
||||||
|
let mut runtime = Runtime {
|
||||||
|
player: tictactoe::Player::X,
|
||||||
|
game: game,
|
||||||
|
};
|
||||||
|
instantiate(x_module, host_module, &runtime)?
|
||||||
|
};
|
||||||
|
let o_instance = {
|
||||||
|
let mut runtime = Runtime {
|
||||||
|
player: tictactoe::Player::O,
|
||||||
|
game: game,
|
||||||
|
};
|
||||||
|
instantiate(o_module, host_module, &runtime)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut turn_of = tictactoe::Player::X;
|
||||||
|
let game_result = loop {
|
||||||
|
let (instance, next_turn_of) = match turn_of {
|
||||||
|
tictactoe::Player::X => (&x_instance, tictactoe::Player::O),
|
||||||
|
tictactoe::Player::O => (&o_instance, tictactoe::Player::X),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut runtime = Runtime {
|
||||||
|
player: turn_of,
|
||||||
|
game: game,
|
||||||
|
};
|
||||||
|
let _ = instance.invoke_export("mk_turn", vec![], &runtime)?;
|
||||||
|
|
||||||
|
match game.game_result() {
|
||||||
|
Some(game_result) => break game_result,
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
turn_of = next_turn_of;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(game_result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let game = tictactoe::Game::new();
|
||||||
|
let env_host_module = env_host_module();
|
||||||
|
|
||||||
|
let args: Vec<_> = env::args().collect();
|
||||||
|
if args.len() < 3 {
|
||||||
|
println!("Usage: {} <x player module> <y player module>", args[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let x_module = parity_wasm::deserialize_file(&args[1]).expect("X player module to load");
|
||||||
|
let o_module = parity_wasm::deserialize_file(&args[2]).expect("Y player module to load");
|
||||||
|
|
||||||
|
let result = play(&x_module, &o_module, &env_host_module, &game);
|
||||||
|
println!("result = {:?}, game = {:#?}", result, game);
|
||||||
|
}
|
@ -84,7 +84,7 @@ impl<St> FuncInstance<St> {
|
|||||||
pub fn invoke(
|
pub fn invoke(
|
||||||
func: Rc<FuncInstance<St>>,
|
func: Rc<FuncInstance<St>>,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
enum InvokeKind<St> {
|
enum InvokeKind<St> {
|
||||||
Internal(FunctionContext<St>),
|
Internal(FunctionContext<St>),
|
||||||
|
@ -11,7 +11,7 @@ use interpreter::value::RuntimeValue;
|
|||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::ImportResolver;
|
use interpreter::ImportResolver;
|
||||||
|
|
||||||
pub type HostFunc<St> = Fn(&mut St, &[RuntimeValue]) -> Result<Option<RuntimeValue>, Error>;
|
pub type HostFunc<St> = Fn(&St, &[RuntimeValue]) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
|
||||||
pub struct HostModuleBuilder<St> {
|
pub struct HostModuleBuilder<St> {
|
||||||
exports: HashMap<String, ExternVal<St>>,
|
exports: HashMap<String, ExternVal<St>>,
|
||||||
@ -25,7 +25,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_func0<
|
pub fn with_func0<
|
||||||
Cl: Fn(&mut St) -> Result<Option<Ret>, Error> + 'static,
|
Cl: Fn(&St) -> Result<Option<Ret>, Error> + 'static,
|
||||||
Ret: AsReturnVal + 'static,
|
Ret: AsReturnVal + 'static,
|
||||||
N: Into<String>,
|
N: Into<String>,
|
||||||
>(
|
>(
|
||||||
@ -34,7 +34,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
f: Cl,
|
f: Cl,
|
||||||
) {
|
) {
|
||||||
let func_type = FunctionType::new(vec![], Ret::value_type());
|
let func_type = FunctionType::new(vec![], Ret::value_type());
|
||||||
let host_func = Rc::new(move |state: &mut St, _args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
let host_func = Rc::new(move |state: &St, _args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
||||||
let result = f(state);
|
let result = f(state);
|
||||||
result.map(|r| r.and_then(|r| r.as_return_val()))
|
result.map(|r| r.and_then(|r| r.as_return_val()))
|
||||||
});
|
});
|
||||||
@ -44,7 +44,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_func1<
|
pub fn with_func1<
|
||||||
Cl: Fn(&mut St, P1) -> Result<Option<Ret>, Error> + 'static,
|
Cl: Fn(&St, P1) -> Result<Option<Ret>, Error> + 'static,
|
||||||
Ret: AsReturnVal + 'static,
|
Ret: AsReturnVal + 'static,
|
||||||
P1: FromArg + 'static,
|
P1: FromArg + 'static,
|
||||||
N: Into<String>,
|
N: Into<String>,
|
||||||
@ -54,7 +54,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
f: Cl,
|
f: Cl,
|
||||||
) {
|
) {
|
||||||
let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type());
|
let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type());
|
||||||
let host_func = Rc::new(move |state: &mut St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
||||||
let arg0 = P1::from_arg(&args[0]);
|
let arg0 = P1::from_arg(&args[0]);
|
||||||
let result = f(state, arg0);
|
let result = f(state, arg0);
|
||||||
result.map(|r| r.and_then(|r| r.as_return_val()))
|
result.map(|r| r.and_then(|r| r.as_return_val()))
|
||||||
@ -65,7 +65,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_func2<
|
pub fn with_func2<
|
||||||
Cl: Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
|
Cl: Fn(&St, P1, P2) -> Result<Option<Ret>, Error> + 'static,
|
||||||
Ret: AsReturnVal + 'static,
|
Ret: AsReturnVal + 'static,
|
||||||
P1: FromArg + 'static,
|
P1: FromArg + 'static,
|
||||||
P2: FromArg + 'static,
|
P2: FromArg + 'static,
|
||||||
@ -76,7 +76,7 @@ impl<St> HostModuleBuilder<St> {
|
|||||||
f: Cl,
|
f: Cl,
|
||||||
) {
|
) {
|
||||||
let func_type = FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type());
|
let func_type = FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type());
|
||||||
let host_func = Rc::new(move |state: &mut St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
let host_func = Rc::new(move |state: &St, args: &[RuntimeValue]| -> Result<Option<RuntimeValue>, Error> {
|
||||||
let p1 = P1::from_arg(&args[0]);
|
let p1 = P1::from_arg(&args[0]);
|
||||||
let p2 = P2::from_arg(&args[1]);
|
let p2 = P2::from_arg(&args[1]);
|
||||||
let result = f(state, p1, p2);
|
let result = f(state, p1, p2);
|
||||||
@ -180,7 +180,7 @@ impl<St> ImportResolver<St> for HostModule<St> {
|
|||||||
pub trait AnyFunc<St> {
|
pub trait AnyFunc<St> {
|
||||||
fn call_as_any(
|
fn call_as_any(
|
||||||
&self,
|
&self,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
) -> Result<Option<RuntimeValue>, Error>;
|
) -> Result<Option<RuntimeValue>, Error>;
|
||||||
}
|
}
|
||||||
@ -228,10 +228,10 @@ impl AsReturnVal for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St, Ret: AsReturnVal> AnyFunc<St> for Fn(&mut St) -> Result<Option<Ret>, Error> {
|
impl<St, Ret: AsReturnVal> AnyFunc<St> for Fn(&St) -> Result<Option<Ret>, Error> {
|
||||||
fn call_as_any(
|
fn call_as_any(
|
||||||
&self,
|
&self,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
_args: &[RuntimeValue],
|
_args: &[RuntimeValue],
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let result = self(state);
|
let result = self(state);
|
||||||
@ -239,10 +239,10 @@ impl<St, Ret: AsReturnVal> AnyFunc<St> for Fn(&mut St) -> Result<Option<Ret>, Er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> AnyFunc<St> for Fn(&mut St, P1, P2) -> Result<Option<Ret>, Error> {
|
impl<St, Ret: AsReturnVal, P1: FromArg, P2: FromArg> AnyFunc<St> for Fn(&St, P1, P2) -> Result<Option<Ret>, Error> {
|
||||||
fn call_as_any(
|
fn call_as_any(
|
||||||
&self,
|
&self,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
args: &[RuntimeValue],
|
args: &[RuntimeValue],
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let p1 = P1::from_arg(&args[0]);
|
let p1 = P1::from_arg(&args[0]);
|
||||||
|
@ -401,7 +401,7 @@ impl<St> ModuleInstance<St> {
|
|||||||
&self,
|
&self,
|
||||||
func_idx: u32,
|
func_idx: u32,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let func_instance = self.func_by_index(func_idx).ok_or_else(|| {
|
let func_instance = self.func_by_index(func_idx).ok_or_else(|| {
|
||||||
Error::Program(format!(
|
Error::Program(format!(
|
||||||
@ -416,7 +416,7 @@ impl<St> ModuleInstance<St> {
|
|||||||
&self,
|
&self,
|
||||||
func_name: &str,
|
func_name: &str,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let extern_val = self.export_by_name(func_name).ok_or_else(|| {
|
let extern_val = self.export_by_name(func_name).ok_or_else(|| {
|
||||||
Error::Program(format!("Module doesn't have export {}", func_name))
|
Error::Program(format!("Module doesn't have export {}", func_name))
|
||||||
@ -466,7 +466,7 @@ impl<'a, St: 'a> InstantiationWizard<'a, St> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_start(mut self, state: &mut St) -> Result<Rc<ModuleInstance<St>>, Error> {
|
pub fn run_start(mut self, state: &St) -> Result<Rc<ModuleInstance<St>>, Error> {
|
||||||
let imports = self.imports.get_or_insert_with(|| Imports::default());
|
let imports = self.imports.get_or_insert_with(|| Imports::default());
|
||||||
let instance = ModuleInstance::instantiate_with_imports(self.module, imports)?;
|
let instance = ModuleInstance::instantiate_with_imports(self.module, imports)?;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ impl<St> ProgramInstance<St> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
module: Module,
|
module: Module,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Rc<ModuleInstance<St>>, Error> {
|
) -> Result<Rc<ModuleInstance<St>>, Error> {
|
||||||
let module_instance = {
|
let module_instance = {
|
||||||
let mut imports = Imports::new();
|
let mut imports = Imports::new();
|
||||||
@ -72,7 +72,7 @@ impl<St> ProgramInstance<St> {
|
|||||||
module_name: &str,
|
module_name: &str,
|
||||||
func_name: &str,
|
func_name: &str,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let module_instance = self.modules.get(module_name).ok_or_else(|| {
|
let module_instance = self.modules.get(module_name).ok_or_else(|| {
|
||||||
Error::Program(format!("Module {} not found", module_name))
|
Error::Program(format!("Module {} not found", module_name))
|
||||||
@ -85,7 +85,7 @@ impl<St> ProgramInstance<St> {
|
|||||||
module_name: &str,
|
module_name: &str,
|
||||||
func_idx: u32,
|
func_idx: u32,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let module_instance = self.modules.get(module_name).cloned().ok_or_else(|| {
|
let module_instance = self.modules.get(module_name).cloned().ok_or_else(|| {
|
||||||
Error::Program(format!("Module {} not found", module_name))
|
Error::Program(format!("Module {} not found", module_name))
|
||||||
@ -97,7 +97,7 @@ impl<St> ProgramInstance<St> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
func_instance: Rc<FuncInstance<St>>,
|
func_instance: Rc<FuncInstance<St>>,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
state: &mut St,
|
state: &St,
|
||||||
) -> Result<Option<RuntimeValue>, Error> {
|
) -> Result<Option<RuntimeValue>, Error> {
|
||||||
FuncInstance::invoke(Rc::clone(&func_instance), args, state)
|
FuncInstance::invoke(Rc::clone(&func_instance), args, state)
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ use common::stack::StackWithLimit;
|
|||||||
|
|
||||||
/// Function interpreter.
|
/// Function interpreter.
|
||||||
pub struct Interpreter<'a, St: 'a> {
|
pub struct Interpreter<'a, St: 'a> {
|
||||||
state: &'a mut St,
|
state: &'a St,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function execution context.
|
/// Function execution context.
|
||||||
@ -64,7 +64,7 @@ enum RunResult<St> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, St: 'a> Interpreter<'a, St> {
|
impl<'a, St: 'a> Interpreter<'a, St> {
|
||||||
pub fn new(state: &'a mut St) -> Interpreter<'a, St> {
|
pub fn new(state: &'a St) -> Interpreter<'a, St> {
|
||||||
Interpreter {
|
Interpreter {
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
///! Basic tests for instructions/constructions, missing in wabt tests
|
///! Basic tests for instructions/constructions, missing in wabt tests
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
use builder::module;
|
use builder::module;
|
||||||
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
|
use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType,
|
||||||
InitExpr, ValueType, Opcodes, Opcode, TableType, MemoryType};
|
InitExpr, ValueType, Opcodes, Opcode, TableType, MemoryType};
|
||||||
@ -118,12 +119,12 @@ impl UserError for UserErrorWithCode {}
|
|||||||
|
|
||||||
struct TestState {
|
struct TestState {
|
||||||
pub memory: Rc<MemoryInstance>,
|
pub memory: Rc<MemoryInstance>,
|
||||||
pub values: Vec<i32>,
|
pub values: RefCell<Vec<i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_env_module() -> HostModule<TestState> {
|
fn build_env_module() -> HostModule<TestState> {
|
||||||
let mut builder = HostModuleBuilder::<TestState>::new();
|
let mut builder = HostModuleBuilder::<TestState>::new();
|
||||||
builder.with_func2("add", |state: &mut TestState, arg: i32, unused: i32| {
|
builder.with_func2("add", |state: &TestState, arg: i32, unused: i32| {
|
||||||
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
||||||
let fn_argument_unused = unused as u8;
|
let fn_argument_unused = unused as u8;
|
||||||
let fn_argument = arg as u8;
|
let fn_argument = arg as u8;
|
||||||
@ -131,10 +132,10 @@ fn build_env_module() -> HostModule<TestState> {
|
|||||||
|
|
||||||
let sum = memory_value + fn_argument;
|
let sum = memory_value + fn_argument;
|
||||||
state.memory.set(0, &vec![sum]).unwrap();
|
state.memory.set(0, &vec![sum]).unwrap();
|
||||||
state.values.push(sum as i32);
|
state.values.borrow_mut().push(sum as i32);
|
||||||
Ok(Some(sum as i32))
|
Ok(Some(sum as i32))
|
||||||
});
|
});
|
||||||
builder.with_func2("sub", |state: &mut TestState, arg: i32, unused: i32| {
|
builder.with_func2("sub", |state: &TestState, arg: i32, unused: i32| {
|
||||||
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
let memory_value = state.memory.get(0, 1).unwrap()[0];
|
||||||
let fn_argument_unused = unused as u8;
|
let fn_argument_unused = unused as u8;
|
||||||
let fn_argument = arg as u8;
|
let fn_argument = arg as u8;
|
||||||
@ -142,10 +143,10 @@ fn build_env_module() -> HostModule<TestState> {
|
|||||||
|
|
||||||
let diff = memory_value - fn_argument;
|
let diff = memory_value - fn_argument;
|
||||||
state.memory.set(0, &vec![diff]).unwrap();
|
state.memory.set(0, &vec![diff]).unwrap();
|
||||||
state.values.push(diff as i32);
|
state.values.borrow_mut().push(diff as i32);
|
||||||
Ok(Some(diff as i32))
|
Ok(Some(diff as i32))
|
||||||
});
|
});
|
||||||
builder.with_func2("err", |_: &mut TestState, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
|
builder.with_func2("err", |_: &TestState, _unused1: i32, _unused2: i32| -> Result<Option<i32>, Error> {
|
||||||
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
|
Err(Error::User(Box::new(UserErrorWithCode { error_code: 777 })))
|
||||||
});
|
});
|
||||||
builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap()));
|
builder.insert_memory("memory", Rc::new(MemoryInstance::new(&MemoryType::new(256, None)).unwrap()));
|
||||||
@ -161,7 +162,7 @@ fn native_env_function() {
|
|||||||
|
|
||||||
let mut state = TestState {
|
let mut state = TestState {
|
||||||
memory: env_memory,
|
memory: env_memory,
|
||||||
values: Vec::new(),
|
values: RefCell::new(Vec::new()),
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
let module = module()
|
let module = module()
|
||||||
@ -212,7 +213,7 @@ fn native_env_function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(state.memory.get(0, 1).unwrap()[0], 42);
|
assert_eq!(state.memory.get(0, 1).unwrap()[0], 42);
|
||||||
assert_eq!(state.values, vec![7, 57, 42]);
|
assert_eq!(&*state.values.borrow(), &[7, 57, 42]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -233,8 +234,8 @@ fn native_env_global() {
|
|||||||
])).build()
|
])).build()
|
||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
program.add_module("main", module, &mut State)?;
|
program.add_module("main", module, &State)?;
|
||||||
program.invoke_index("main", 0, vec![], &mut State)
|
program.invoke_index("main", 0, vec![], &State)
|
||||||
};
|
};
|
||||||
|
|
||||||
// try to add module, exporting non-existant env' variable => error
|
// try to add module, exporting non-existant env' variable => error
|
||||||
@ -260,7 +261,7 @@ fn native_custom_error() {
|
|||||||
|
|
||||||
let mut state = TestState {
|
let mut state = TestState {
|
||||||
memory: env_memory,
|
memory: env_memory,
|
||||||
values: Vec::new(),
|
values: RefCell::new(Vec::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let module = module()
|
let module = module()
|
||||||
@ -297,7 +298,7 @@ fn native_ref_state() {
|
|||||||
|
|
||||||
// This structure holds state for our host module.
|
// This structure holds state for our host module.
|
||||||
struct HostState<'a> {
|
struct HostState<'a> {
|
||||||
ext_state: &'a mut ExtState,
|
ext_state: RefCell<&'a mut ExtState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let main_module = module()
|
let main_module = module()
|
||||||
@ -322,8 +323,13 @@ fn native_ref_state() {
|
|||||||
let mut host_module_builder = HostModuleBuilder::<HostState>::new();
|
let mut host_module_builder = HostModuleBuilder::<HostState>::new();
|
||||||
host_module_builder.with_func1(
|
host_module_builder.with_func1(
|
||||||
"inc",
|
"inc",
|
||||||
|state: &mut HostState, val: i32| -> Result<Option<()>, Error> {
|
|state: &HostState, val: i32| -> Result<Option<()>, Error> {
|
||||||
*state.ext_state += val;
|
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(None)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -331,7 +337,7 @@ fn native_ref_state() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut host_state = HostState {
|
let mut host_state = HostState {
|
||||||
ext_state: &mut ext_state,
|
ext_state: RefCell::new(&mut ext_state),
|
||||||
};
|
};
|
||||||
|
|
||||||
let instance = ModuleInstance::instantiate(&main_module)
|
let instance = ModuleInstance::instantiate(&main_module)
|
||||||
|
Reference in New Issue
Block a user