nowasm
is a WebAssembly 1.0 runtime that is implemented with no-std, no-unsafe and no-dependencies.
The goal is to provide a lightweight WebAssembly runtime that can be embedded wherever Rust is used, with a particular focus on Wasm-in-Wasm scenarios.
- Add validation phase (TBD)
- Add doc comments
- Add more tests
nowasm
supports the following extensions necessary to run WebAssembly binaries built with the latest stable Rust compiler.
Please execute the command $ cargo build --target wasm32-unknown-unknown --example hello
to build the following "Hello World!" printing code (examples/wasm/hello.rs) into a WebAssembly binary:
extern "C" {
fn print(s: *const u8, len: i32);
}
#[no_mangle]
pub fn hello() {
let msg = "Hello, World!\n";
unsafe {
print(msg.as_ptr(), msg.len() as i32);
}
}
Then, you can execute the hello()
function via the following command:
$ cargo run --example call_hello
Hello, World!
The code of examples/call_hello.rs is as follows:
use nowasm::{Env, HostFunc, Module, Resolve, StdVectorFactory, Val};
pub fn main() {
let wasm_bytes = include_bytes!("../target/wasm32-unknown-unknown/debug/examples/hello.wasm");
let module = Module::<StdVectorFactory>::decode(wasm_bytes).expect("Failed to decode module");
let mut instance = module
.instantiate(Resolver)
.expect("Failed to instantiate module");
instance
.invoke("hello", &[])
.expect("Failed to invoke function");
}
struct Resolver;
impl Resolve for Resolver {
type HostFunc = Print;
fn resolve_func(&self, module: &str, name: &str) -> Option<Self::HostFunc> {
assert_eq!(module, "env");
assert_eq!(name, "print");
Some(Print)
}
}
struct Print;
impl HostFunc for Print {
fn invoke(&mut self, args: &[Val], env: &mut Env) -> Option<Val> {
let ptr = args[0].as_i32().expect("Not a i32") as usize;
let len = args[1].as_i32().expect("Not a i32") as usize;
let msg = std::str::from_utf8(&env.mem[ptr..ptr + len]).expect("Invalid utf8");
print!("{msg}");
None
}
}