DEV Community

Brandon Fish for Wasmer

Posted on

Embedding WebAssembly in your Rust application

Wasmer is a WebAssembly runtime designed to run both standalone and embedded.

The crate wasmer-runtime exposes an easy to use and safe api for compiling, creating imports, and calling WebAssembly from your own library.

Rust-Wasmer

This tutorial goes over how to make a simple wasm application and run it using the wasmer-runtime!

Creating a Wasm Application

Our sample application is just a basic “Hello, World!” program. Because WebAssembly doesn’t inherently have any way to print to the command line, we have to import such a function from our environment.

In this case, we define an imported print_str function.

// Define a function that is imported into the module.
// By default, the "env" namespace is used.
extern "C" {
    fn print_str(ptr: *const u8, len: usize);
}

// Define a string that is accessible within the wasm
// linear memory.
static HELLO: &'static str = "Hello, World!";

// Export a function named "hello_wasm". This can be called
// from the embedder!
#[no_mangle]
pub extern fn hello_wasm() {
    // Call the function we just imported and pass in
    // the offset of our string and its length as parameters.
    unsafe {
      print_str(HELLO.as_ptr(), HELLO.len());
    }
}

When the hello_wasm function is called by the embedder, it will proceed to call the imported print_str function with a pointer to the “Hello, World!” string and its length as arguments.

Embedding WebAssembly using Wasmer!

This example shows to use use the wasmer-runtime crate to compile and run WebAssembly!

Since our Wasm application imported a function print_str, we must create an ImportObject containing the implementation of that function.

While you can manually (and unsafely) fill in the import object yourself, we’ve defined a useful macro that does function signature checking automatically to make it easier and safer.

use std::str;
use wasmer_runtime::{
    imports,
    instantiate,
    error,
    Ctx,
};

// Make sure that the compiled wasm-sample-app is accessible at this path.
static WASM: &'static [u8] = include_bytes!("../wasm-sample-app/target/wasm32-unknown-unknown/release/wasm_sample_app.wasm");

fn main() -> error::Result<()> {
    // Let's define the import object used to import our function
    // into our webassembly sample application.
    //
    // We've defined a macro that makes it super easy.
    //
    // The signature tells the runtime what the signature (the parameter
    // and return types) of the function we're defining here is.
    // The allowed types are `i32`, `u32`, `i64`, `u64`,
    // `f32`, and `f64`.
    //
    // Make sure to check this carefully!
    let import_object = imports! {
        // Define the "env" namespace that was implicitly used
        // by our sample application.
        "env" => {
            // name         // func    // signature
            "print_str" => print_str<[u32, u32] -> []>,
        },
    };

    // Compile our webassembly into an `Instance`.
    let mut instance = instantiate(WASM, import_object)?;

    // Call our exported function!
    instance.call("hello_wasm", &[])?;

    Ok(())
}

// Let's define our "print_str" function.
//
// The declaration must start with "extern" or "extern "C"".
extern fn print_str(ptr: u32, len: u32, ctx: &mut Ctx) {
    // Get a slice that maps to the memory currently used by the webassembly
    // instance.
    //
    // Webassembly only supports a single memory for now,
    // but in the near future, it'll support multiple.
    //
    // Therefore, we don't assume you always just want to access first
    // memory and force you to specify the first memory.
    let memory = ctx.memory(0);

    // Get a subslice that corresponds to the memory used by the string.
    let str_slice = &memory[ptr as usize..(ptr + len) as usize];

    // Convert the subslice to a `&str`.
    let string = str::from_utf8(str_slice).unwrap();

    // Print it!
    println!("{}", string);
}

This example is hosted on Github. Check out the Readme for instructions on how to try it out for yourself!

Example of Using Wasmer from Rust

If you have feedback, issues, or feature requests please open an issue in our Github repository.

We look forward to what cool things you build with WebAssembly and our new embeddable runtime!

Top comments (0)