Learning Rust+Wasm

 from Red Blob Games
28 Dec 2019

Table of Contents

I wanted to try a simple Rust+Wasm example. I’m following the instructions from - https://github.com/AndrewThian/learn-wasm-rust[1]. I created the project:

rustup target add wasm32-unknown-unknown
cargo install wasm-gc
cargo install wasm-bindgen-cli
cargo new --lib 1952-learning-rust-wasm

Here’s how I compiled it:

cargo build --target wasm32-unknown-unknown --release
wasm-gc target/wasm32-unknown-unknown/release/1952_learning_rust_wasm.wasm learning.gc.wasm

I had to add the application/wasm wasm mime type to the apache/nginx config.

Here’s the output:

The wasm-bindgen[2] tool generates javascript glue to handle types other than numbers. The --browser flag makes a js module, and does not include the above code to load the wasm. The --target no-modules flag makes a top level definition, and does include code to load the wasm. See these docs[3] for the glue code. This tool seems to automatically run wasm-gc for you. See the list of types[4]: number, bool, str, char, arrays of js values, iterables[5], js functions[6], rust functions[7], promises/futures[8].

The js-sys[9] Rust library exposes all the JS APIs: data types (arrays, set, map, date, etc.), proxy, regexp, uri functions, exception objects, etc. The web-sys[10] Rust library exposes all the browser APIs: DOM, window, audio, svg, webgl, canvas, websockets[11], etc.

wasm-bindgen --debug --target no-modules target/wasm32-unknown-unknown/release/1952_learning_rust_wasm.wasm --out-dir build/

 1  Size#

Seems to 5835 bytes for heap allocation:

# twiggy top build/1952_learning_rust_wasm_bg.wasm | grep Dl
3236 ┊    33.79% ┊ dlmalloc::dlmalloc::Dlmalloc::malloc::h363feeec79793de2
 941 ┊     9.83% ┊ dlmalloc::dlmalloc::Dlmalloc::free::h57aed881a8c806e8
 651 ┊     6.80% ┊ dlmalloc::dlmalloc::Dlmalloc::dispose_chunk::h1db030999ec3b24a
 365 ┊     3.81% ┊ dlmalloc::dlmalloc::Dlmalloc::memalign::ha7187a0adc17c42a
 327 ┊     3.41% ┊ dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk::h1fcac6f829185c8b
 315 ┊     3.29% ┊ dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk::hafa48d776dcd75a2
# twiggy top build/1952_learning_rust_wasm_bg.wasm | grep Dl | awk '{sum += $1} END {print sum}'
5835

 2  Sources#

Then edited Cargo.toml:

[package]
name = "1952_learning_rust_wasm"
version = "0.1.0"
authors = ["Amit Patel <redblobgames@gmail.com>"]
edition = "2018"

[lib]
crate-type = ["cdylib"]

[profile.release]
lto = true
opt-level = 'z'

[dependencies]
wasm-bindgen = "0.2"

Here’s the source src/lib.rs:

use wasm_bindgen::prelude::*;

static MEMORY_TEST: &str = "Hello, World";

macro_rules! log {
    ($($t:tt)*) => (console_log_str(&format!($($t)*)))
}

#[wasm_bindgen]
extern "C" {
    fn call_me_str(x: &str);

    #[wasm_bindgen(js_namespace = console, js_name = log)]
    fn console_log_str(s: &str);
}

#[wasm_bindgen]
pub fn add_one(x: u32) -> u32 {
    x + 1
}

#[wasm_bindgen]
pub fn return_str(x: &str) -> String {
    x.to_string()
}

#[wasm_bindgen]
pub fn return_vec(x: &str) -> Vec<u8> {
    x.to_string().into_bytes()
}

#[wasm_bindgen]
pub fn return_array() -> *const u8 {
    MEMORY_TEST.as_ptr()
}

#[wasm_bindgen]
pub fn return_arraylen() -> usize {
    MEMORY_TEST.len()
}

#[wasm_bindgen]
pub fn pass_in_str(x: &str, y: String) -> String {
    let mut a = x.to_string();
    a.push_str(&y);
    log!("pass_in_str({}, {}) -> {}", x, y, a);
    a
}

#[wasm_bindgen]
pub fn call_fn(x: &str) {
    call_me_str(x);
}

 3  More#

Email me , or tweet @redblobgames, or comment: