Move examples and adapt.
This commit is contained in:
parent
3bd8f8a250
commit
e9a414d504
|
@ -1,18 +1,23 @@
|
||||||
|
//! A simple tic tac toe implementation.
|
||||||
|
//!
|
||||||
|
//! You specify two wasm modules with a certain ABI and this
|
||||||
|
//! program instantiates these modules and runs a module
|
||||||
|
//! on turn-by-turn basis.
|
||||||
|
//!
|
||||||
|
|
||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
extern crate wasmi;
|
extern crate wasmi;
|
||||||
|
extern crate wasmi_derive;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use wasmi::{
|
use wasmi::{Error as InterpreterError, HostError, ImportsBuilder, ModuleInstance, ModuleRef};
|
||||||
Error as InterpreterError, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder,
|
|
||||||
ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeArgs, RuntimeValue, Signature, Trap,
|
|
||||||
ValueType,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
OutOfRange,
|
OutOfRange,
|
||||||
|
AlreadyPlayed,
|
||||||
AlreadyOccupied,
|
AlreadyOccupied,
|
||||||
Interpreter(InterpreterError),
|
Interpreter(InterpreterError),
|
||||||
}
|
}
|
||||||
|
@ -46,16 +51,6 @@ mod tictactoe {
|
||||||
Won(Player),
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
board: [Option<Player>; 9],
|
board: [Option<Player>; 9],
|
||||||
|
@ -133,59 +128,40 @@ mod tictactoe {
|
||||||
|
|
||||||
struct Runtime<'a> {
|
struct Runtime<'a> {
|
||||||
player: tictactoe::Player,
|
player: tictactoe::Player,
|
||||||
|
made_turn: bool,
|
||||||
game: &'a mut tictactoe::Game,
|
game: &'a mut tictactoe::Game,
|
||||||
}
|
}
|
||||||
|
|
||||||
const SET_FUNC_INDEX: usize = 0;
|
#[wasmi_derive::derive_externals]
|
||||||
const GET_FUNC_INDEX: usize = 1;
|
impl<'a> Runtime<'a> {
|
||||||
|
/// Puts a mark of the current player on the given cell.
|
||||||
|
///
|
||||||
|
/// Traps if the index is out of bounds of game field or if the player
|
||||||
|
/// already made it's turn.
|
||||||
|
pub fn set(&mut self, idx: i32) -> Result<(), Error> {
|
||||||
|
if self.made_turn {
|
||||||
|
return Err(Error::AlreadyPlayed);
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Externals for Runtime<'a> {
|
|
||||||
fn invoke_index(
|
|
||||||
&mut self,
|
|
||||||
index: usize,
|
|
||||||
args: RuntimeArgs,
|
|
||||||
) -> Result<Option<RuntimeValue>, Trap> {
|
|
||||||
match index {
|
|
||||||
SET_FUNC_INDEX => {
|
|
||||||
let idx: i32 = args.nth(0);
|
|
||||||
self.game.set(idx, self.player)?;
|
self.game.set(idx, self.player)?;
|
||||||
Ok(None)
|
Ok(())
|
||||||
}
|
}
|
||||||
GET_FUNC_INDEX => {
|
|
||||||
let idx: i32 = args.nth(0);
|
|
||||||
let val: i32 = tictactoe::Player::into_i32(self.game.get(idx)?);
|
|
||||||
Ok(Some(val.into()))
|
|
||||||
}
|
|
||||||
_ => panic!("unknown function index"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RuntimeModuleImportResolver;
|
/// Returns the player index at the specified cell.
|
||||||
|
///
|
||||||
|
/// 0 - unoccupied
|
||||||
|
/// 1 - player X
|
||||||
|
/// 2 - player O
|
||||||
|
///
|
||||||
|
/// Traps if the index is out of bounds of game field.
|
||||||
|
pub fn get(&self, idx: i32) -> Result<i32, Error> {
|
||||||
|
use tictactoe::Player;
|
||||||
|
|
||||||
impl<'a> ModuleImportResolver for RuntimeModuleImportResolver {
|
Ok(match self.game.get(idx)? {
|
||||||
fn resolve_func(
|
None => 0,
|
||||||
&self,
|
Some(Player::X) => 1,
|
||||||
field_name: &str,
|
Some(Player::O) => 2,
|
||||||
_signature: &Signature,
|
})
|
||||||
) -> Result<FuncRef, InterpreterError> {
|
|
||||||
let func_ref = match field_name {
|
|
||||||
"set" => FuncInstance::alloc_host(
|
|
||||||
Signature::new(&[ValueType::I32][..], None),
|
|
||||||
SET_FUNC_INDEX,
|
|
||||||
),
|
|
||||||
"get" => FuncInstance::alloc_host(
|
|
||||||
Signature::new(&[ValueType::I32][..], Some(ValueType::I32)),
|
|
||||||
GET_FUNC_INDEX,
|
|
||||||
),
|
|
||||||
_ => {
|
|
||||||
return Err(InterpreterError::Function(format!(
|
|
||||||
"host module doesn't export function with name {}",
|
|
||||||
field_name
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(func_ref)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,10 +174,14 @@ fn instantiate(path: &str) -> Result<ModuleRef, Error> {
|
||||||
wasmi::Module::from_buffer(&wasm_buf)?
|
wasmi::Module::from_buffer(&wasm_buf)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut imports = ImportsBuilder::new();
|
let instance = {
|
||||||
imports.push_resolver("env", &RuntimeModuleImportResolver);
|
let resolver = Runtime::resolver();
|
||||||
|
|
||||||
let instance = ModuleInstance::new(&module, &imports)?.assert_no_start();
|
let mut imports = ImportsBuilder::new();
|
||||||
|
imports.push_resolver("env", &resolver);
|
||||||
|
|
||||||
|
ModuleInstance::new(&module, &imports)?.assert_no_start()
|
||||||
|
};
|
||||||
|
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
@ -222,6 +202,7 @@ fn play(
|
||||||
let mut runtime = Runtime {
|
let mut runtime = Runtime {
|
||||||
player: turn_of,
|
player: turn_of,
|
||||||
game: game,
|
game: game,
|
||||||
|
made_turn: false,
|
||||||
};
|
};
|
||||||
let _ = instance.invoke_export("mk_turn", &[], &mut runtime)?;
|
let _ = instance.invoke_export("mk_turn", &[], &mut runtime)?;
|
||||||
}
|
}
|
Loading…
Reference in New Issue