/nowasm

No-std, no-unsafe and no-dependencies WebAssembly 1.0 runtime for Rust

Primary LanguageRustMIT LicenseMIT

nowasm

nowasm Documentation Actions Status License

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.

TODO list until v0.1.0

  • Add validation phase (TBD)
  • Add doc comments
  • Add more tests

Supported Extensions

nowasm supports the following extensions necessary to run WebAssembly binaries built with the latest stable Rust compiler.

Examples

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
    }
}