How do I get comiple rust code in wasm?

I'm trying compile the bellow code in web browser. It is code for tictac game written in rust-lang. I wanted to play the game in server.

extern crate wasmi;
extern crate parity_wasm;

use std::env;
use std::fmt;
use std::fs::File;
use wasmi::{
	Error as InterpreterError, ModuleInstance, ModuleRef,
	Externals, RuntimeValue, FuncRef, ModuleImportResolver,
	FuncInstance, HostError, ImportsBuilder, Signature, ValueType,
	RuntimeArgs, Trap,
};

#[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 HostError for Error {}

mod tictactoe {
	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: [Option<Player>; 9],
	}

	impl Game {
		pub fn new() -> Game {
			Game {
				board: [None; 9],
			}
		}

		pub fn set(&mut self, idx: i32, player: Player) -> Result<(), Error> {
			if idx < 0 || idx > 9 {
				return Err(Error::OutOfRange);
			}
			if self.board[idx as usize] != None {
				return Err(Error::AlreadyOccupied);
			}
			self.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[idx as usize])
		}

		pub fn game_result(&self) -> Option<GameResult> {
			// 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 self.board[i1].is_none() {
					return None;
				}
				if self.board[i1] == self.board[i2] && self.board[i2] == self.board[i3] {
					return self.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 = self.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 mut tictactoe::Game,
}

const SET_FUNC_INDEX: usize = 0;
const GET_FUNC_INDEX: usize = 1;

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)?;
				Ok(None)
			}
			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;

impl<'a> ModuleImportResolver for RuntimeModuleImportResolver {
	fn resolve_func(
		&self,
		field_name: &str,
		_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)
	}
}

fn instantiate(path: &str) -> Result<ModuleRef, Error> {
	let module = {
		use std::io::prelude::*;
		let mut file = File::open(path).unwrap();
		let mut wasm_buf = Vec::new();
		file.read_to_end(&mut wasm_buf).unwrap();
		wasmi::Module::from_buffer(&wasm_buf)?
	};

	let mut imports = ImportsBuilder::new();
	imports.push_resolver("env", &RuntimeModuleImportResolver);

	let instance = ModuleInstance::new(&module, &imports)?
		.assert_no_start();

	Ok(instance)
}

fn play(
	x_instance: ModuleRef,
	o_instance: ModuleRef,
	game: &mut tictactoe::Game,
) -> Result<tictactoe::GameResult, Error> {
	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", &[], &mut runtime)?;
		}

		match game.game_result() {
			Some(game_result) => break game_result,
			None => {}
		}

		turn_of = next_turn_of;
	};

	Ok(game_result)
}

fn main() {
	let mut game = tictactoe::Game::new();

	let args: Vec<_> = env::args().collect();
	if args.len() < 3 {
		println!("Usage: {} <x player module> <y player module>", args[0]);
		return;
	}

	// Instantiate modules of X and O players.
	let x_instance = instantiate(&args[1]).expect("X player module to load");
	let o_instance = instantiate(&args[2]).expect("Y player module to load");

	let result = play(x_instance, o_instance, &mut game);
	println!("result = {:?}, game = {:#?}", result, game);
}

Building is done using command cargo build --target wasm32-unknown-unknown When I run the command cargo web start --target wasm32-unknown-unknown to run it in server I’m getting blank page with the message Finished loading Rust wasm module tests.js

So I tried with rustc --target=wasm32-unknown-unknown hello.rs -o hello.html
Getting following error.

error[E0463]: can't find crate for `wasmi`
 --> hello.rs:1:1
  |
1 | extern crate wasmi;
  | ^^^^^^^^^^^^^^^^^^^ can't find crate

error: aborting due to previous error

For more information about this error, try `rustc --explain E0463`.

I already run the command rustup target add wasm32-unknown-unknown
info: component ‘rust-std’ for target ‘wasm32-unknown-unknown’ is up to date.

rustc -V
rustc 1.30.0-nightly (5c875d938 2018-09-24)

rustup -V
rustup 1.13.0 (ea9259c1b 2018-07-16)

Can anyone help how to run above code in server.
Thanks

Why don't you use your old thread anymore, but instead open a new one? :confused:

Next question, why do you still use pure rustc (after you have succesfully used cargo?!)?

Just to give more clarification I created new thread. (code is added)

Yeah building is successful but it is not running in server. How to proceed after building?

There's a little more to running a wasm file than there is when launching normal compiled output for a native platform. The wasm needs to be wrapped in a web page and some javascript.

Please work your way through the rust wasm book which will help you with this. (link to a page that's a good overview, but start at the beginning for setup) Hello, World! - Rust and WebAssembly

1 Like