What's a WASM?
What is WebAssembly and how do you use it from Rust?

06 March 2018

If you’ve been watching the developments in the Rust programming language over the last few months, you might have heard mention of something called WebAssembly. I know I’ve dropped the word into this blog a few times without really explaining what it is.

WebAssembly is a relatively new format for code that runs on the web. Unlike JavaScript, which is meant for humans to be able to read, WebAssembly is intended to be used as an output format to allow programming languages like C++ or Rust target web browsers. It’s a low level assembly language, but for running in web browsers.

Inspiration from the Past

Those of you who have been in web development for a while might be thinking that this sounds terribly familiar. Isn’t this pretty much how you might have described Java Applets twenty years ago?

A big difference between WebAssembly and things like Java Applets, Flash, or Google Native Client is that it’s designed to work more harmoniously with the rest of the web ecosystem. Java Applets could be embedded in web pages, but after they were launched they pretty much did their own thing, running their own virtual machine with different APIs into the computer and different permission structures. There was a time when you’d embed Flash in a page to do things that could not be done using JavaScript, like video players and copying to the clipboard.

WebAssembly, by contrast, coexists with the JavaScript on a page. JavaScript code can call WebAssembly, and WebAssembly can call back into JavaScript. In fact, it’s designed to be implemented inside the existing JavaScript sandboxing technologies, so also avoid the additional security issues with having browser plugins running native code. Luckily, the APIs that JavaScript have access to have also evolved into something more fully featured since the days when Flash was necessary.

If the user didn’t have Java installed already they’d have to go install it. If you’re lucky, they’re willing to do so, aren’t blocked by corporate policies, and then keep it up to date. Google Native Client didn’t need a separate plugin, but it was a Google Chrome specific feature that the other browsers didn’t really pick up.

WebAssembly is a web standard, which isn’t owned by any particular browser vendor but is shaped by representatives from several major browsers.

The technology that most naturally comes before WebAssembly in my opinion is something called Asm.js. Asm.js was an idea for compiling C and C++ code into a subset of JavaScript. The Asm.js compiler is a program called Emscripten, which now also has support for WebAssembly.

Where can I run WebAssembly?

The first version of the standard (they’re calling it the minimum viable product) has been stable since February 2017, and is currently available in the latest versions of all major web browsers. In other words, if your customer base is using modern web browsers, you can now use WebAssembly to run code.

This includes many modern smart phones as well.

I’ve personally used WebAssembly to build my Rusty Microphone project, which does real time pitch analysis of audio from your microphone. I’ve also seen WebAssembly used in a really cool little browser platformer game. I’m sure we’ll see more and more things making use of WebAssembly as time goes on.

How do I use this from Rust?

There are a small number of languages that you can compile to WebAssembly, including C, C++ and Rust. If you’ve been reading my blog for a while, you’ll know that I’m a fan of Rust so I’m going to focus on compiling Rust.

Installing the Nightly Compiler

WebAssembly is a new technology, and support for compiling to it from Rust is even newer. So new in fact, that it isn’t in the stable release of the Rust compiler yet. The good news though is if you’re using Rustup to manage your Rust tool-chain it’s really easy to install the nightly release of the compiler and use it in just this one case.

These two commands to Rustup will download the WebAssembly compiler to your computer.

rustup toolchain install nightly
rustup target add wasm32-unknown-unknown --toolchain nightly

That’s it. You now have the WebAssembly tools. Now you need to look at the Cargo.toml in your Rust project. If you’re working on a binary crate (like an application), then you don’t need to change anything. If you’re writing a library, then you’ll need to change your crate type to cdylib by adding this little snippet.

path = "src/lib.rs"
crate-type = ["cdylib"]

You can now compile to WebAssembly using this Cargo command.

cargo +nightly build --target wasm32-unknown-unknown --release

Take a look in target/wasm32-unknown-unknown/release/ to find a file with the extension .wasm. That’s the brand new WebAssembly build of your project!

I usually add a Makefile to automate running that long Cargo command and copying the WebAssembly file to a folder with some other JavaScript and HTML files.

Instantiating from JavaScript

WebAssembly isn’t a standalone format yet. You need to load it from within JavaScript. My Rusty Microphone project has a block to load the WebAssembly that looks like this:

// If your Rust code declares external functions, then you need to
// provide JavaScript implementations. At this stage, some of the core
// Maths routines need this.
var env = {
    log2f: Math.log2,
    roundf: Math.round

// Fetch will create a network request to get the file.
    .then(response => response.arrayBuffer())
    .then(bytes => WebAssembly.instantiate(bytes, { env:env }))
    .then(results => {
        // After instantiating the WebAssembly, you have an 'instance'
        // of it. This will expose all of your Rust code's external
        // public functions.

function main(wasmExports) {
    // Do the things that require WebAssembly to be loaded
    // Like call exported functions
    wasmExports.add(2, 2);

More complicated data structures

One complication that you run into fairly quickly is that WebAssembly has a very small number of types. There are integers and floating point numbers. That’s it. This doesn’t directly affect most of your Rust code, since the compiler handles representing everything as numbers, but it does make passing different types from JavaScript more complicated.

This is a small list of different types I’ve experimented with. All of them rely to some extent on the idea of pointers.

Pointers, if you haven’t heard of them before, are a special type of variable often used in low level programming. I think the best way to get your head around pointers is to imagine your computer’s memory as a massive array of bytes. A pointer would be an index into that array of bytes. A pointer with a value of 5 is ‘pointing to’ the data in memory at index 5.

Pointers are an absolutely essential feature of programming, but also make it very easy to shoot yourself in the foot. That’s why most high level languages hide pointers behind abstractions that manage some of their complexity, like passing data by reference.

Back to the topic of WebAssembly, a pointer is an integer, so it can be passed from JavaScript to Rust.


To pass a JavaScript array to your Rust code, you need four things:

  1. A way to allocate memory that Rust has access to for the array.
  2. A way to free the memory afterwards.
  3. A way to copy your array into that memory.
  4. A way to call the Rust function that needs the array, such that it can read the data.

The first two we’ll accomplish by writing Rust functions for allocating and freeing blocks of memory. Notice the * in the types. These indicate that the values are pointers.

// Rust
pub extern "C" fn malloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();

    // Take buf out of scope without releaseing its memory.
    return ptr as *mut c_void;

pub extern "C" fn free(ptr: *mut c_void, cap: usize) {
    // dereferencing a raw pointer is always unsafe. You don't know where
    // it's been.
    unsafe  {
        // after it's back in scope, it can go out of scope in the
        // normal RAII cleanup.
        let _buf = Vec::from_raw_parts(ptr, 0, cap);

The next step is, in JavaScript, calling these functions and copying your data into it. In my codebase, my function to do this is as follows:

// JavaScript
function jsArrayToPtr(jsArray, callback) {
    // your array needs to be in a JavaScript typed array.
    var data = new Float32Array(jsArray);
    var byteLength = data.length * data.BYTES_PER_ELEMENT;
    var dataPtr = wasmExports.malloc(byteLength);

    // wasmExports.memory is your WebAssembly program's memory. All of
    // it. You can read from it or, as we're doing here, write to it.
    var heap = new Uint8Array(
        wasmExports.memory.buffer, dataPtr, byteLength
    heap.set(new Uint8Array(data.buffer));

    // callback is whichever functions wants to use the array in the
    // new form. Note that it needs the pointer and the number of
    // elements.
    var result = callback(dataPtr, jsArray.length);

    // always remember to clean up your memory when you're done.
    wasmExports.free(dataPtr, byteLength);  
    return result;

Using this functions to call my Rusty Microphone’s “find fundamental frequency” function would look like this:

// JavaScript
function findFundamentalFrequency(data, sampleRate) {
    return jsArrayToPtr(data, function(ptr, length) {
        return wasmExports.find_fundamental_frequency(
            ptr, length, sampleRate

This example of course isn’t complete without the Rust code that’s being called.

pub extern "C" fn find_fundamental_frequency(signal_ptr: *const f32,
                                             signal_length: usize,
                                             sample_rate: f32) -> f32 {
    // Rust has functions for building a slice from a pointer and
    // length. It's just unsafe to use it because Rust can't control
    // what JavaScript passed in.
    let signal_slice = unsafe {
        &slice::from_raw_parts(signal_ptr, signal_length)

    // Once we've made out input a slice, we can call our normal happy
    // Rust code as before.
    let signal = Signal::new(signal_slice, sample_rate);
    let model = Model::from_signal(signal);

    // My pitch is an Option<f32>, but I can only return ints and
    // floats, so I make use of NAN for the None case.
    model.pitch.map_or(f32::NAN, |p| p.hz)

Returning arrays can be a bit more complicated. A convention that you can borrow from the C programming language is to pass in the array that the results need to be written into as well. You can then read the results from the the WebAssembly memory before calling free on the pointer.


You can pass strings to and from WebAssembly functions using “C-style” strings. That is, a pointer to an array of characters with the requirement that the last character in your string is a null.

For example, here is my Rust function that formats the pitch for me to print on the screen.

// Rust
pub extern "C" fn hz_to_pitch(hz: f32) -> *mut c_char {
    let pitch = Pitch::new(hz);
    CString::new(format!("{}", pitch))

Taking this pointer back to JavaScript string is a bit less comfortable. One key point for reading them is that Rust uses UTF-8 formatted strings.

// JavaScript
function readCStr(ptr) {
    var memory = new Uint8Array(wasmExports.memory.buffer);

    // finds the length of the string by searching for null
    var length = 0;
    while (memory[ptr + length] !== 0) {
        length += 1;
    return new TextDecoder("UTF-8").decode(memory.subarray(ptr, ptr+length));

Passing a string into a function would be a similar exercise, but using a TextEncoder rather than a TextDecoder. As with the arrays, don’t forget to free your pointers once you’re done with them.


Rust structs don’t have a nice JavaScript equivalent. The easiest option would be to keep your Rust structs in Rust, referring to them in JavaScript only using pointers that came from Rust.

A second option is to use a serialization library such as Serde. With Serde, you can serialize your Rust struct to a Json string, use the method described above to pass the Json string back to JavaScript, and then deserialize it into a JavaScript object. You can also use Serde to deserialize a Json string that was generated by JavaScript.

Integrate with Web APIs

Calling WebAssembly functions from JavaScript isn’t the whole story. The other half is calling JavaScript functions from WebAssembly. In a future version of WebAssembly you might be able to call the various APIs directly from WebAssembly, but for now you need to manually write your own bindings between the two.

Calling a JavaScript function

There are two sides to calling a JavaScript function from Rust. The first is that you need to declare in your Rust program that the function will exist when the WebAssembly code is instantiated. The other side is passing the actual implementation.

// Rust
extern {
    pub fn redrawUI(w: c_int, h: c_int);

Passing that JavaScript function to WebAssembly is as simple as having it on an object passed through to the WebAssembly’s instantiation. If you forget this step, the WebAssembly will throw an error when it’s instantiated.

// JavaScript

function redrawUI(w, h) {
    // rendering logic here

var env = {
    redrawUI: redrawUI

    .then(response => response.arrayBuffer())
    .then(bytes => WebAssembly.instantiate(bytes, { env:env }))
    .then(results => {
        // as before, do things with results.instance.exports here.

Libraries to make things easier

OK, so most of the things I’ve listed up there look like a lot of effort to get small amounts of things done. Things are moving quickly, and both the tools and the standard itself are going to develop to make things easier eventually. For now though, there are some crates that you can use to make things a bit easier.


If you’re trying to call a lot of Web APIs from your Rust code, like building HTML components in Rust, there’s stdweb. It provides a library for accessing the various APIs of the web, including manipulating HTML and embedding JavaScript directly into your Rust code.


I haven’t used this one personally, but it looks like a fantastic tool to automate writing that wrapper code between JavaScript and Rust yourself. wasm-bindgen is a Rust library and a command line tool that, together, generate a nice JavaScript interface to your Rust code, including letting you pass in array, strings and JavaScript objects. In other words, it would let you write the public APIs that you want to be using, and then generate the JavaScript and WebAssembly code to make it work.

That’s it for now, but I’m sure there will be more to come

I hope this whirlwind tour of Rust and WebAssembly will inspire you to write your own web code in Rust. The boundaries around the WebAssembly code still feel a bit rough, but this may change the way we think about web applications. At the very least, hopefully it results in us seeing some new exciting things that we didn’t expect to appear in our web browsers.