Rust and WebAssembly
Rust and WebAssembly
💡 Tip: You can search through this book by clicking on the 🔍 icon
at the top of the page, or by pressing the s key.
https://rustwasm.github.io/docs/book/print.html 1/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 2/97
1/15/25, 10:07 AM Rust and WebAssembly
What is WebAssembly?
WebAssembly (wasm) is a simple machine model and executable format
with an extensive specification. It is designed to be portable, compact,
https://rustwasm.github.io/docs/book/print.html 3/97
1/15/25, 10:07 AM Rust and WebAssembly
(module
(func $fac (param f64) (result f64)
local.get 0
f64.const 1
f64.lt
if (result f64)
f64.const 1
else
local.get 0
local.get 0
f64.const 1
f64.sub
call $fac
f64.mul
end)
(export "fac" (func $fac)))
If you're curious about what a wasm file looks like you can use the
wat2wasm demo with the above code.
Linear Memory
WebAssembly has a very simple memory model. A wasm module has
access to a single "linear memory", which is essentially a flat array of
bytes. This memory can be grown by a multiple of the page size (64K). It
cannot be shrunk.
https://rustwasm.github.io/docs/book/print.html 4/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 5/97
1/15/25, 10:07 AM Rust and WebAssembly
Setup
This section describes how to set up the toolchain for compiling Rust
programs to WebAssembly and integrate them into JavaScript.
wasm-pack
cargo-generate
https://rustwasm.github.io/docs/book/print.html 6/97
1/15/25, 10:07 AM Rust and WebAssembly
cargo-generate helps you get up and running quickly with a new Rust
project by leveraging a pre-existing git repository as a template.
Install cargo-generate with this command:
npm
npm is a package manager for JavaScript. We will use it to install and run a
JavaScript bundler and development server. At the end of the tutorial, we
will publish our compiled .wasm to the npm registry.
Follow these instructions to install npm .
If you already have npm installed, make sure it is up to date with this
command:
Hello, World!
This section will show you how to build and run your first Rust and
WebAssembly program: a Web page that alerts "Hello, World!"
Make sure you have followed the setup instructions before beginning.
This should prompt you for the new project's name. We will use "wasm-
game-of-life".
wasm-game-of-life
What's Inside
Enter the new wasm-game-of-life project
cd wasm-game-of-life
wasm-game-of-life/
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
└── src
├── lib.rs
└── utils.rs
wasm-game-of-life/Cargo.toml
wasm-game-of-life/src/lib.rs
https://rustwasm.github.io/docs/book/print.html 8/97
1/15/25, 10:07 AM Rust and WebAssembly
The src/lib.rs file is the root of the Rust crate that we are compiling to
WebAssembly. It uses wasm-bindgen to interface with JavaScript. It imports
the window.alert JavaScript function, and exports the greet Rust
function, which alerts a greeting message.
mod utils;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet() {
alert("Hello, wasm-game-of-life!");
}
wasm-game-of-life/src/utils.rs
https://rustwasm.github.io/docs/book/print.html 9/97
1/15/25, 10:07 AM Rust and WebAssembly
wasm-pack build
When the build has completed, we can find its artifacts in the pkg
directory, and it should have these contents:
pkg/
├── package.json
├── README.md
├── wasm_game_of_life_bg.wasm
├── wasm_game_of_life.d.ts
└── wasm_game_of_life.js
The README.md file is copied from the main project, but the others are
completely new.
wasm-game-of-life/pkg/wasm_game_of_life_bg.wasm
The .wasm file is the WebAssembly binary that is generated by the Rust
compiler from our Rust sources. It contains the compiled-to-wasm
versions of all of our Rust functions and data. For example, it has an
exported "greet" function.
wasm-game-of-life/pkg/wasm_game_of_life.js
when we start passing more interesting values back and forth between
wasm and JavaScript, it will help shepherd those values across the
boundary.
// ...
wasm-game-of-life/pkg/wasm_game_of_life.d.ts
The .d.ts file contains TypeScript type declarations for the JavaScript
glue. If you are using TypeScript, you can have your calls into
WebAssembly functions type checked, and your IDE can provide
autocompletions and suggestions! If you aren't using TypeScript, you can
safely ignore this file.
wasm-game-of-life/pkg/package.json
https://rustwasm.github.io/docs/book/print.html 11/97
1/15/25, 10:07 AM Rust and WebAssembly
{
"name": "wasm-game-of-life",
"collaborators": [
"Your Name <your.email@example.com>"
],
"description": null,
"version": "0.1.0",
"license": null,
"repository": null,
"files": [
"wasm_game_of_life_bg.wasm",
"wasm_game_of_life.d.ts"
],
"main": "wasm_game_of_life.js",
"types": "wasm_game_of_life.d.ts"
}
wasm-game-of-life/www/
├── bootstrap.js
├── index.html
├── index.js
├── LICENSE-APACHE
├── LICENSE-MIT
├── package.json
├── README.md
└── webpack.config.js
wasm-game-of-life/www/package.json
https://rustwasm.github.io/docs/book/print.html 12/97
1/15/25, 10:07 AM Rust and WebAssembly
wasm-game-of-life/www/webpack.config.js
This file configures webpack and its local development server. It comes
pre-configured, and you shouldn't have to tweak this at all to get webpack
and its local development server working.
wasm-game-of-life/www/index.html
This is the root HTML file for the Web page. It doesn't do much other than
load bootstrap.js , which is a very thin wrapper around index.js .
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
</head>
<body>
<script src="./bootstrap.js"></script>
</body>
</html>
wasm-game-of-life/www/index.js
The index.js is the main entry point for our Web page's JavaScript. It
imports the hello-wasm-pack npm package, which contains the default
wasm-pack-template 's compiled WebAssembly and JavaScript glue, then it
calls hello-wasm-pack 's greet function.
https://rustwasm.github.io/docs/book/print.html 13/97
1/15/25, 10:07 AM Rust and WebAssembly
wasm.greet();
npm install
This command only needs to be run once, and will install the webpack
JavaScript bundler and its development server.
Note that webpack is not required for working with Rust and
WebAssembly, it is just the bundler and development server we've
chosen for convenience here. Parcel and Rollup should also support
importing WebAssembly as ECMAScript modules. You can also use
Rust and WebAssembly without a bundler if you prefer!
Rather than use the hello-wasm-pack package from npm, we want to use
our local wasm-game-of-life package instead. This will allow us to
incrementally develop our Game of Life program.
Open up wasm-game-of-life/www/package.json and next to
"devDependencies" , add the "dependencies" field, including a
"wasm-game-of-life": "file:../pkg" entry:
https://rustwasm.github.io/docs/book/print.html 14/97
1/15/25, 10:07 AM Rust and WebAssembly
{
// ...
"dependencies": { // Add this three lines
block!
"wasm-game-of-life": "file:../pkg"
},
"devDependencies": {
//...
}
}
wasm.greet();
npm install
Serving Locally
Next, open a new terminal for the development server. Running the
server in a new terminal lets us leave it running in the background, and
doesn't block us from running other commands in the meantime. In the
new terminal, run this command from within the wasm-game-of-life/www
directory:
https://rustwasm.github.io/docs/book/print.html 15/97
1/15/25, 10:07 AM Rust and WebAssembly
Exercises
Modify the function in wasm-game-of-life/src/lib.rs to take a
greet
name: &str parameter that customizes the alerted message, and
pass your name to the greet function from inside
wasm-game-of-life/www/index.js . Rebuild the .wasm binary with
wasm-pack build , then refresh http://localhost:8080/ in your Web
browser and you should see a customized greeting!
Answer
https://rustwasm.github.io/docs/book/print.html 16/97
1/15/25, 10:07 AM Rust and WebAssembly
3. Any live cell with more than three live neighbours dies, as if by
overpopulation.
4. Any dead cell with exactly three live neighbours becomes a live
cell, as if by reproduction.
The initial pattern constitutes the seed of the system. The first
generation is created by applying the above rules simultaneously to
every cell in the seed—births and deaths occur simultaneously, and
the discrete moment at which this happens is sometimes called a tick
(in other words, each generation is a pure function of the preceding
one). The rules continue to be applied repeatedly to create further
generations.
Next Universe
From these simple, deterministic rules, strange and exciting behavior
emerges:
Exercises
Compute by hand the next tick of our example universe. Notice
anything familiar?
Answer
Can you find an initial universe that is stable? That is, a universe in
which every generation is always the same.
https://rustwasm.github.io/docs/book/print.html 18/97
1/15/25, 10:07 AM Rust and WebAssembly
Answer
Design
Before we dive in, we have some design choices to consider.
Infinite Universe
The Game of Life is played in an infinite universe, but we do not have
infinite memory and compute power. Working around this rather
annoying limitation usually comes in one of three flavors:
1. Keep track of which subset of the universe has interesting things
happening, and expand this region as needed. In the worst case, this
expansion is unbounded and the implementation will get slower and
slower and eventually run out of memory.
2. Create a fixed-size universe, where cells on the edges have fewer
neighbors than cells in the middle. The downside with this approach
is that infinite patterns, like gliders, that reach the end of the universe
are snuffed out.
3. Create a fixed-size, periodic universe, where cells on the edges have
neighbors that wrap around to the other side of the universe.
Because neighbors wrap around the edges of the universe, gliders
can keep running forever.
We will implement the third option.
https://rustwasm.github.io/docs/book/print.html 19/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 20/97
1/15/25, 10:07 AM Rust and WebAssembly
This Rust String is then copied from the WebAssembly linear memory into
a JavaScript String in the JavaScript's garbage-collected heap, and is then
displayed by setting HTML textContent . Later in the chapter, we'll evolve
this implementation to avoid copying the universe's cells between heaps
and to render to <canvas> .
Another viable design alternative would be for Rust to return a list of every cell
that changed states after each tick, instead of exposing the whole universe to
JavaScript. This way, JavaScript wouldn't need to iterate over the whole
universe when rendering, only the relevant subset. The trade off is that this
delta-based design is slightly more difficult to implement.
Rust Implementation
In the last chapter, we cloned an initial project template. We will modify
that project template now.
Let's begin by removing the import and greet function from
alert
wasm-game-of-life/src/lib.rs , and replacing them with a type definition
for cells:
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
Dead = 0,
Alive = 1,
}
https://rustwasm.github.io/docs/book/print.html 22/97
1/15/25, 10:07 AM Rust and WebAssembly
#[wasm_bindgen]
pub struct Universe {
width: u32,
height: u32,
cells: Vec<Cell>,
}
To access the cell at a given row and column, we translate the row and
column into an index into the cells vector, as described earlier:
impl Universe {
fn get_index(&self, row: u32, column: u32) -> usize {
(row * self.width + column) as usize
}
// ...
}
In order to calculate the next state of a cell, we need to get a count of how
many of its neighbors are alive. Let's write a live_neighbor_count method
to do just that!
impl Universe {
// ...
https://rustwasm.github.io/docs/book/print.html 23/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 24/97
1/15/25, 10:07 AM Rust and WebAssembly
next[idx] = next_cell;
}
}
self.cells = next;
}
// ...
}
https://rustwasm.github.io/docs/book/print.html 25/97
1/15/25, 10:07 AM Rust and WebAssembly
alive, print the Unicode character ◼ ("black medium square"). For dead
cells, we'll print ◻ (a "white medium square").
use std::fmt;
Ok(())
}
}
https://rustwasm.github.io/docs/book/print.html 26/97
1/15/25, 10:07 AM Rust and WebAssembly
Universe {
width,
height,
cells,
}
}
With that, the Rust half of our Game of Life implementation is complete!
Recompile it to WebAssembly by running wasm-pack build within the
wasm-game-of-life directory.
https://rustwasm.github.io/docs/book/print.html 27/97
1/15/25, 10:07 AM Rust and WebAssembly
<body>
<pre id="game-of-life-canvas"></pre>
<script src="./bootstrap.js"></script>
</body>
Additionally, we want the <pre> centered in the middle of the Web page.
We can use CSS flex boxes to accomplish this task. Add the following
<style> tag inside wasm-game-of-life/www/index.html 's <head> :
<style>
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
</style>
Also, let's get that <pre> element we just added and instantiate a new
universe:
requestAnimationFrame(renderLoop);
};
https://rustwasm.github.io/docs/book/print.html 28/97
1/15/25, 10:07 AM Rust and WebAssembly
To start the rendering process, all we have to do is make the initial call for
the first iteration of the rendering loop:
requestAnimationFrame(renderLoop);
Make sure your development server is still running (run npm run start
inside wasm-game-of-life/www ) and this is what http://localhost:8080/
should look like:
Screenshot of the Game of Life implementation with text rendering
<body>
<canvas id="game-of-life-canvas"></canvas>
<script src='./bootstrap.js'></script>
</body>
https://rustwasm.github.io/docs/book/print.html 29/97
1/15/25, 10:07 AM Rust and WebAssembly
const CELL_SIZE = 5; // px
const GRID_COLOR = "#CCCCCC";
const DEAD_COLOR = "#FFFFFF";
const ALIVE_COLOR = "#000000";
Now, let's rewrite the rest of this JavaScript code to no longer write to the
<pre> 's textContent but instead draw to the <canvas> :
https://rustwasm.github.io/docs/book/print.html 30/97
1/15/25, 10:07 AM Rust and WebAssembly
// Give the canvas room for all of our cells and a 1px border
// around each of them.
const canvas = document.getElementById("game-of-life-canvas");
canvas.height = (CELL_SIZE + 1) * height + 1;
canvas.width = (CELL_SIZE + 1) * width + 1;
drawGrid();
drawCells();
requestAnimationFrame(renderLoop);
};
// Vertical lines.
for (let i = 0; i <= width; i++) {
ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);
ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height +
1);
}
// Horizontal lines.
for (let j = 0; j <= height; j++) {
ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);
ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);
}
ctx.stroke();
};
// ...
ctx.beginPath();
ctx.fillRect(
col * (CELL_SIZE + 1) + 1,
row * (CELL_SIZE + 1) + 1,
CELL_SIZE,
CELL_SIZE
);
}
}
ctx.stroke();
};
To start the rendering process, we'll use the same code as above to start
the first iteration of the rendering loop:
drawGrid();
drawCells();
requestAnimationFrame(renderLoop);
https://rustwasm.github.io/docs/book/print.html 32/97
1/15/25, 10:07 AM Rust and WebAssembly
It Works!
Rebuild the WebAssembly and bindings glue by running this command
from within the root wasm-game-of-life directory:
wasm-pack build
Make sure your development server is still running. If it isn't, start it again
from within the wasm-game-of-life/www directory:
https://rustwasm.github.io/docs/book/print.html 33/97
1/15/25, 10:07 AM Rust and WebAssembly
Exercises
Initialize the universe with a single space ship.
Instead of hard-coding the initial universe, generate a random one,
where each cell has a fifty-fifty chance of being alive or dead.
Hint: use the js-sys crate to import the Math.random JavaScript
function.
Answer
Representing each cell with a byte makes iterating over cells easy, but
it comes at the cost of wasting memory. Each byte is eight bits, but
we only require a single bit to represent whether each cell is alive or
dead. Refactor the data representation so that each cell uses only a
single bit of space.
Answer
https://rustwasm.github.io/docs/book/print.html 34/97
1/15/25, 10:07 AM Rust and WebAssembly
#[wasm_bindgen]
impl Universe {
// ...
https://rustwasm.github.io/docs/book/print.html 35/97
1/15/25, 10:07 AM Rust and WebAssembly
impl Universe {
/// Get the dead and alive values of the entire universe.
pub fn get_cells(&self) -> &[Cell] {
&self.cells
}
https://rustwasm.github.io/docs/book/print.html 36/97
1/15/25, 10:07 AM Rust and WebAssembly
calculated manually. You can confirm for yourself that the cells of the
input spaceship after one tick is the same as the expected spaceship.
#[cfg(test)]
pub fn input_spaceship() -> Universe {
let mut universe = Universe::new();
universe.set_width(6);
universe.set_height(6);
universe.set_cells(&[(1,2), (2,3), (3,1), (3,2), (3,3)]);
universe
}
#[cfg(test)]
pub fn expected_spaceship() -> Universe {
let mut universe = Universe::new();
universe.set_width(6);
universe.set_height(6);
universe.set_cells(&[(2,1), (2,3), (3,2), (3,3), (4,2)]);
universe
}
Now we will write the implementation for our test_tick function. First,
we create an instance of our input_spaceship() and our
expected_spaceship() . Then, we call tick on the input_universe . Finally,
we use the assert_eq! macro to call get_cells() to ensure that
input_universe and expected_universe have the same Cell array values.
We add the #[wasm_bindgen_test] attribute to our code block so we can
test our Rust-generated WebAssembly code and use wasm-pack test to
test the WebAssembly code.
https://rustwasm.github.io/docs/book/print.html 37/97
1/15/25, 10:07 AM Rust and WebAssembly
#[wasm_bindgen_test]
pub fn test_tick() {
// Let's create a smaller Universe with a small spaceship to
test!
let mut input_universe = input_spaceship();
// Call `tick` and then see if the cells in the `Universe`s are
the same.
input_universe.tick();
assert_eq!(&input_universe.get_cells(),
&expected_universe.get_cells());
}
Debugging
Before we write much more code, we will want to have some debugging
tools in our belt for when things go wrong. Take a moment to review the
reference page listing tools and approaches available for debugging Rust-
generated WebAssembly.
https://rustwasm.github.io/docs/book/print.html 38/97
1/15/25, 10:07 AM Rust and WebAssembly
// ...
}
[dependencies]
# ...
[dependencies.web-sys]
version = "0.3"
features = [
"console",
]
https://rustwasm.github.io/docs/book/print.html 39/97
1/15/25, 10:07 AM Rust and WebAssembly
+ log!(
+ "cell[{}, {}] is initially {:?} and has {} live
neighbors",
+ row,
+ col,
+ cell,
+ live_neighbors
+ );
+
let next_cell = match (cell, live_neighbors) {
// Rule 1: Any live cell with fewer than two
live neighbours
// dies, as if caused by underpopulation.
@@ -140,6 +147,8 @@ impl Universe {
(otherwise, _) => otherwise,
};
https://rustwasm.github.io/docs/book/print.html 40/97
1/15/25, 10:07 AM Rust and WebAssembly
drawGrid();
drawCells();
requestAnimationFrame(renderLoop);
};
Exercises
Add logging to the tick function that records the row and column of
each cell that transitioned states from live to dead or vice versa.
Introduce a panic!() in the Universe::new method. Inspect the
panic's backtrace in your Web browser's JavaScript debugger. Disable
debug symbols, rebuild without the console_error_panic_hook
optional dependency, and inspect the stack trace again. Not as useful
is it?
Adding Interactivity
We will continue to explore the JavaScript and WebAssembly interface by
adding some interactive features to our Game of Life implementation. We
will enable users to toggle whether a cell is alive or dead by clicking on it,
and allow pausing the game, which makes drawing cell patterns a lot
easier.
https://rustwasm.github.io/docs/book/print.html 41/97
1/15/25, 10:07 AM Rust and WebAssembly
<button id="play-pause"></button>
https://rustwasm.github.io/docs/book/print.html 42/97
1/15/25, 10:07 AM Rust and WebAssembly
universe.tick();
animationId = requestAnimationFrame(renderLoop);
};
At any instant in time, we can tell whether the game is paused or not by
inspecting the value of animationId :
Now, when the play/pause button is clicked, we check whether the game
is currently paused or playing, and resume the renderLoop animation or
cancel the next animation frame respectively. Additionally, we update the
button's text icon to reflect the action that the button will take when
clicked next.
https://rustwasm.github.io/docs/book/print.html 43/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 44/97
1/15/25, 10:07 AM Rust and WebAssembly
impl Cell {
fn toggle(&mut self) {
*self = match *self {
Cell::Dead => Cell::Alive,
Cell::Alive => Cell::Dead,
};
}
}
To toggle the state of a cell at given row and column, we translate the row
and column pair into an index into the cells vector and call the toggle
method on the cell at that index:
This method is defined within the impl block that is annotated with
#[wasm_bindgen] so that it can be called by JavaScript.
https://rustwasm.github.io/docs/book/print.html 45/97
1/15/25, 10:07 AM Rust and WebAssembly
universe.toggle_cell(row, col);
drawGrid();
drawCells();
});
Exercises
Introduce an <input type="range"> widget to control how many ticks
occur per animation frame.
Add a button that resets the universe to a random initial state when
clicked. Another button that resets the universe to all dead cells.
On Ctrl + Click , insert a glider centered on the target cell. On
Shift + Click , insert a pulsar.
Time Profiling
In this chapter, we will improve the performance of our Game of Life
implementation. We will use time profiling to guide our efforts.
https://rustwasm.github.io/docs/book/print.html 46/97
1/15/25, 10:07 AM Rust and WebAssembly
Familiarize yourself with the available tools for time profiling Rust and
WebAssembly code before continuing.
https://rustwasm.github.io/docs/book/print.html 47/97
1/15/25, 10:07 AM Rust and WebAssembly
render() {
// Convert the delta time since the last frame render into a
measure
// of frames per second.
const now = performance.now();
const delta = now - this.lastFrameTimeStamp;
this.lastFrameTimeStamp = now;
const fps = 1 / delta * 1000;
// Find the max, min, and mean of our 100 latest timings.
let min = Infinity;
let max = -Infinity;
let sum = 0;
for (let i = 0; i < this.frames.length; i++) {
sum += this.frames[i];
min = Math.min(this.frames[i], min);
max = Math.max(this.frames[i], max);
}
let mean = sum / this.frames.length;
https://rustwasm.github.io/docs/book/print.html 48/97
1/15/25, 10:07 AM Rust and WebAssembly
universe.tick();
drawGrid();
drawCells();
animationId = requestAnimationFrame(renderLoop);
};
<div id="fps"></div>
#fps {
white-space: pre;
font-family: monospace;
}
[dependencies.web-sys]
version = "0.3"
features = [
"console",
]
impl<'a> Timer<'a> {
pub fn new(name: &'a str) -> Timer<'a> {
console::time_with_label(name);
Timer { name }
}
}
Then, we can time how long each Universe::tick takes by adding this
snippet to the top of the method:
The time of how long each call to Universe::tick took are now logged in
the console:
Screenshot of console.time logs
Additionally, console.time and console.timeEnd pairs will show up in your
browser's profiler's "timeline" or "waterfall" view:
Screenshot of console.time logs
What happens if we make our Game of Life universe larger? Replacing the
64 by 64 universe with a 128 by 128 universe (by modifying Universe::new
in wasm-game-of-life/src/lib.rs ) results in FPS dropping from a smooth
60 to a choppy 40-ish on my machine.
If we record a profile and look at the waterfall view, we see that each
animation frame is taking over 20 milliseconds. Recall that 60 frames per
second leaves sixteen milliseconds for the whole process of rendering a
frame. That's not just our JavaScript and WebAssembly, but also
everything else the browser is doing, such as painting.
Screenshot of a waterfall view of rendering a frame
If we look at what happens within a single animation frame, we see that
the CanvasRenderingContext2D.fillStyle setter is very expensive!
⚠️ In Firefox, if you see a line that simply says "DOM" instead of the
CanvasRenderingContext2D.fillStyle mentioned above, you may need
to turn on the option for "Show Gecko Platform Data" in your
performance developer tools options:
Turning on Show Gecko Platform Data
focus, since time may be spent in places you don't expect it to be.
ctx.fillRect(
col * (CELL_SIZE + 1) + 1,
row * (CELL_SIZE + 1) + 1,
CELL_SIZE,
CELL_SIZE
);
}
}
https://rustwasm.github.io/docs/book/print.html 52/97
1/15/25, 10:07 AM Rust and WebAssembly
// Alive cells.
ctx.fillStyle = ALIVE_COLOR;
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const idx = getIndex(row, col);
if (cells[idx] !== Cell.Alive) {
continue;
}
ctx.fillRect(
col * (CELL_SIZE + 1) + 1,
row * (CELL_SIZE + 1) + 1,
CELL_SIZE,
CELL_SIZE
);
}
}
// Dead cells.
ctx.fillStyle = DEAD_COLOR;
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const idx = getIndex(row, col);
if (cells[idx] !== Cell.Dead) {
continue;
}
ctx.fillRect(
col * (CELL_SIZE + 1) + 1,
row * (CELL_SIZE + 1) + 1,
CELL_SIZE,
CELL_SIZE
);
}
}
https://rustwasm.github.io/docs/book/print.html 54/97
1/15/25, 10:07 AM Rust and WebAssembly
{
let _timer = Timer::new("new generation");
for row in 0..self.height {
for col in 0..self.width {
let idx = self.get_index(row, col);
let cell = self.cells[idx];
let live_neighbors = self.live_neighbor_count(row,
col);
next[idx] = next_cell;
}
}
}
https://rustwasm.github.io/docs/book/print.html 55/97
1/15/25, 10:07 AM Rust and WebAssembly
#![feature(test)]
#[bench]
fn universe_ticks(b: &mut test::Bencher) {
let mut universe = wasm_game_of_life::Universe::new();
b.iter(|| {
universe.tick();
});
}
https://rustwasm.github.io/docs/book/print.html 56/97
1/15/25, 10:07 AM Rust and WebAssembly
running 0 tests
Running target/release/deps/bench-8474091a05cfa2d9
running 1 test
test universe_ticks ... bench: 664,421 ns/iter (+/- 51,926)
This also tells us where the binary lives, and we can run the benchmarks
again, but this time under our operating system's profiler. In my case, I'm
running Linux, so perf is the profiler I'll use:
Loading up the profile with perf report shows that all of our time is
spent in Universe::tick , as expected:
Screenshot of perf report
perf will annotate which instructions in a function time is being spent at
if you press a :
Screenshot of perf's instruction annotation
This tells us that 26.67% of time is being spent summing neighboring cells'
values, 23.41% of time is spent getting the neighbor's column index, and
another 15.42% of time is spent getting the neighbor's row index. Of
these top three most expensive instructions, the second and third are
https://rustwasm.github.io/docs/book/print.html 57/97
1/15/25, 10:07 AM Rust and WebAssembly
both costly div instructions. These div s implement the modulo indexing
logic in Universe::live_neighbor_count .
Recall the live_neighbor_count definition inside
wasm-game-of-life/src/lib.rs :
The reason we used modulo was to avoid cluttering up the code with if
branches for the first or last row or column edge cases. But we are paying
the cost of a div instruction even for the most common case, when
neither row nor column is on the edge of the universe and they don't
need the modulo wrapping treatment. Instead, if we use if s for the edge
cases and unroll this loop, the branches should be very well-predicted by
the CPU's branch predictor.
Let's rewrite live_neighbor_count like this:
https://rustwasm.github.io/docs/book/print.html 58/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 59/97
1/15/25, 10:07 AM Rust and WebAssembly
count
}
Now let's run the benchmarks again! This time output it to after.txt .
running 0 tests
Running target/release/deps/bench-8474091a05cfa2d9
running 1 test
test universe_ticks ... bench: 87,258 ns/iter (+/- 14,632)
That looks a whole lot better! We can see just how much better it is with
the benchcmp tool and the two text files we created before:
Success!
Screenshot of a waterfall view of rendering a frame after replacing
modulos with branches
Exercises
At this point, the next lowest hanging fruit for speeding up
Universe::tick is removing the allocation and free. Implement
double buffering of cells, where the Universe maintains two vectors,
never frees either of them, and never allocates new buffers in tick .
Implement the alternative, delta-based design from the
"Implementing Life" chapter, where the Rust code returns a list of
cells that changed states to JavaScript. Does this make rendering to
<canvas> faster? Can you implement this design without allocating a
new list of deltas on every tick?
As our profiling has shown us, 2D <canvas> rendering is not
particularly fast. Replace the 2D canvas renderer with a WebGL
renderer. How much faster is the WebGL version? How large can you
make the universe before WebGL rendering is a bottleneck?
https://rustwasm.github.io/docs/book/print.html 61/97
1/15/25, 10:07 AM Rust and WebAssembly
$ wc -c pkg/wasm_game_of_life_bg.wasm
29410 pkg/wasm_game_of_life_bg.wasm
After enabling LTO, setting opt-level = "z" , and running wasm-opt -Oz ,
the resulting .wasm binary shrinks to only 17,317 bytes:
$ wc -c pkg/wasm_game_of_life_bg.wasm
17317 pkg/wasm_game_of_life_bg.wasm
And if we compress it with gzip (which nearly every HTTP server does) we
get down to a measly 9,045 bytes!
Exercises
Use the wasm-snip tool to remove the panicking infrastructure
functions from our Game of Life's .wasm binary. How many bytes
does it save?
Build our Game of Life crate with and without wee_alloc as its global
allocator. The rustwasm/wasm-pack-template template that we cloned
to start this project has a "wee_alloc" cargo feature that you can
enable by adding it to the default key in the [features] section of
wasm-game-of-life/Cargo.toml :
https://rustwasm.github.io/docs/book/print.html 62/97
1/15/25, 10:07 AM Rust and WebAssembly
[features]
default = ["wee_alloc"]
How much size does using wee_alloc shave off of the .wasm binary?
We only ever instantiate a single Universe , so rather than providing a
constructor, we can export operations that manipulate a single
static mut global instance. If this global instance also uses the
double buffering technique discussed in earlier chapters, we can
make those buffers also be static mut globals. This removes all
dynamic allocation from our Game of Life implementation, and we
can make it a #![no_std] crate that doesn't include an allocator. How
much size was removed from the .wasm by completely removing the
allocator dependency?
Publishing to npm
Now that we have a working, fast, and small wasm-game-of-life package,
we can publish it to npm so other JavaScript developers can reuse it, if
they ever need an off-the-shelf Game of Life implementation.
Prerequisites
First, make sure you have an npm account.
Second, make sure you are logged into your account locally, by running
this command:
wasm-pack login
https://rustwasm.github.io/docs/book/print.html 63/97
1/15/25, 10:07 AM Rust and WebAssembly
Publishing
Make sure that the wasm-game-of-life/pkg build is up to date by running
wasm-pack inside the wasm-game-of-life directory:
wasm-pack build
wasm-pack publish
[package]
name = "wasm-game-of-life-my-username"
wasm-pack build
wasm-pack publish
Reference
This section contains reference material for Rust and WebAssembly
development. It is not intended to provide a narrative and be read start to
finish. Instead, each subsection should stand on its own.
https://rustwasm.github.io/docs/book/print.html 64/97
1/15/25, 10:07 AM Rust and WebAssembly
https://rustwasm.github.io/docs/book/print.html 65/97
1/15/25, 10:07 AM Rust and WebAssembly
Dynamic Allocation
https://rustwasm.github.io/docs/book/print.html 66/97
1/15/25, 10:07 AM Rust and WebAssembly
wasm-pack | repository
wasm-pack seeks to be a one-stop shop for building and working with
Rust- generated WebAssembly that you would like to interoperate with
JavaScript, on the Web or with Node.js. wasm-pack helps you build and
publish Rust-generated WebAssembly to the npm registry to be used
alongside any other JavaScript package in workflows that you already use.
wasm-opt | repository
The wasm-opt tool reads WebAssembly as input, runs transformation,
optimization, and/or instrumentation passes on it, and then emits the
transformed WebAssembly as output. Running it on the .wasm binaries
produced by LLVM by way of rustc will usually create .wasm binaries that
are both smaller and execute faster. This tool is a part of the binaryen
project.
wasm2js | repository
The wasm2js tool compiles WebAssembly into "almost asm.js". This is
great for supporting browsers that don't have a WebAssembly
implementation, such as Internet Explorer 11. This tool is a part of the
binaryen project.
https://rustwasm.github.io/docs/book/print.html 68/97
1/15/25, 10:07 AM Rust and WebAssembly
wasm-gc | repository
A small tool to garbage collect a WebAssembly module and remove all
unneeded exports, imports, functions, etc. This is effectively a
--gc-sections linker flag for WebAssembly.
You don't usually need to use this tool yourself because of two reasons:
1. now has a new enough version of lld that it supports the
rustc
--gc-sections flag for WebAssembly. This is automatically enabled
for LTO builds.
2. The wasm-bindgen CLI tool runs wasm-gc for you automatically.
wasm-snip | repository
wasm-snip replaces a WebAssembly function's body with an unreachable
instruction.
Maybe you know that some function will never be called at runtime, but
the compiler can't prove that at compile time? Snip it! Then run wasm-gc
again and all the functions it transitively called (which could also never be
called at runtime) will get removed too.
This is useful for forcibly removing Rust's panicking infrastructure in non-
debug production builds.
twiggy | repository
twiggy is a code size profiler for .wasm binaries. It analyzes a binary's call
graph to answer questions like:
Why was this function included in the binary in the first place? I.e.
which exported functions are transitively calling it?
https://rustwasm.github.io/docs/book/print.html 69/97
1/15/25, 10:07 AM Rust and WebAssembly
What is the retained size of this function? I.e. how much space would
be saved if I removed it and all the functions that become dead code
after its removal.
Use twiggy to make your binaries slim!
wasm-objdump | repository
Print low-level details about a .wasm binary and each of its sections. Also
supports disassembling into the WAT text format. It's like objdump but for
WebAssembly. This is a part of the WABT project.
wasm-nm | repository
List the imported, exported, and private function symbols defined within
a .wasm binary. It's like nm but for WebAssembly.
Project Templates
The Rust and WebAssembly working group curates and maintains a
variety of project templates to help you kickstart new projects and hit the
ground running.
wasm-pack-template
https://rustwasm.github.io/docs/book/print.html 70/97
1/15/25, 10:07 AM Rust and WebAssembly
create-wasm-app
This template is for JavaScript projects that consume packages from npm
that were created from Rust with wasm-pack .
Use it with npm init :
mkdir my-project
cd my-project/
npm init wasm-app
rust-webpack-template
This template comes pre-configured with all the boilerplate for compiling
Rust to WebAssembly and hooking that directly into a Webpack build
pipeline with Webpack's rust-loader .
Use it with npm init :
mkdir my-project
cd my-project/
npm init rust-webpack
Debugging Rust-Generated
WebAssembly
This section contains tips for debugging Rust-generated WebAssembly.
⚡ When debugging, always make sure you are building with debug
symbols!
If you don't have debug symbols enabled, then the "name" custom
section won't be present in the compiled .wasm binary, and stack traces
will have function names like wasm-function[42] rather than the Rust
name of the function, like
wasm_game_of_life::Universe::live_neighbor_count .
When using a "debug" build (aka wasm-pack build --debug or cargo build
) debug symbols are enabled by default.
With a "release" build, debug symbols are not enabled by default. To
enable debug symbols, ensure that you debug = true in the
[profile.release] section of your Cargo.toml :
[profile.release]
debug = true
web_sys::console::log_1(&"Hello, world!".into());
References
Using console.log with the
crate: web-sys
web_sys::console::log takes an array of values to log
web_sys::console::log_1 logs a single value
web_sys::console::log_2 logs two values
Etc...
Using console.error with the web-sys crate:
web_sys::console::error takes an array of values to log
web_sys::console::error_1 logs a single value
web_sys::console::error_2 logs two values
Etc...
The console object on MDN
Firefox Developer Tools — Web Console
Microsoft Edge Developer Tools — Console
Get Started with the Chrome DevTools Console
Logging Panics
The console_error_panic_hook crate logs unexpected panics to the
developer console via console.error . Rather than getting cryptic, difficult-
to-debug RuntimeError: unreachable executed error messages, this gives
you Rust's formatted panic message.
All you need to do is install the hook by calling
console_error_panic_hook::set_once() in an initialization function or
common code path:
#[wasm_bindgen]
pub fn init_panic_hook() {
console_error_panic_hook::set_once();
}
https://rustwasm.github.io/docs/book/print.html 73/97
1/15/25, 10:07 AM Rust and WebAssembly
Using a Debugger
Unfortunately, the debugging story for WebAssembly is still immature. On
most Unix systems, DWARF is used to encode the information that a
debugger needs to provide source-level inspection of a running program.
There is an alternative format that encodes similar information on
Windows. Currently, there is no equivalent for WebAssembly. Therefore,
debuggers currently provide limited utility, and we end up stepping
through raw WebAssembly instructions emitted by the compiler, rather
than the Rust source text we authored.
Nonetheless, debuggers are still useful for inspecting the JavaScript that
interacts with our WebAssembly, and inspecting raw wasm state.
References
Firefox Developer Tools — Debugger
Microsoft Edge Developer Tools — Debugger
Get Started with Debugging JavaScript in Chrome DevTools
test cases. Ultimately, you will have an easier time finding and fixing bugs
if you can isolate them in a smaller test cases that don't require
interacting with JavaScript.
Note that in order to run native #[test] s without compiler and linker
errors, you will need to ensure that "rlib" is included in the
[lib.crate-type] array in your Cargo.toml file.
[lib]
crate-type ["cdylib", "rlib"]
Time Profiling
This section describes how to profile Web pages using Rust and
WebAssembly where the goal is improving throughput or latency.
Available Tools
The window.performance.now() Timer
The performance.now() function returns a monotonic timestamp
measured in milliseconds since the Web page was loaded.
Calling performance.now has little overhead, so we can create simple,
granular measurements from it without distorting the performance of the
rest of the system and inflicting bias upon our measurements.
We can use it to time various operations, and we can access
window.performance.now() via the web-sys crate:
https://rustwasm.github.io/docs/book/print.html 75/97
1/15/25, 10:07 AM Rust and WebAssembly
Resources
https://rustwasm.github.io/docs/book/print.html 77/97
1/15/25, 10:07 AM Rust and WebAssembly
Resources
https://rustwasm.github.io/docs/book/print.html 78/97
1/15/25, 10:07 AM Rust and WebAssembly
hand, can often take longer to not only parse but also get up to speed
with JIT compilation and such.
And finally, remember that WebAssembly is also far more optimized than
JavaScript for execution speed. You'll want to be sure to measure for
runtime comparisons between JavaScript and WebAssembly to factor that
in to how important code size is.
All this to say basically don't dismay immediately if your .wasm file is
larger than expected! Code size may end up only being one of many
factors in the end-to-end story. Comparisons between JavaScript and
WebAssembly that only look at code size are missing the forest for the
trees.
[profile.release]
lto = true
This gives LLVM many more opportunities to inline and prune functions.
Not only will it make the .wasm smaller, but it will also make it faster at
runtime! The downside is that compilation will take longer.
https://rustwasm.github.io/docs/book/print.html 79/97
1/15/25, 10:07 AM Rust and WebAssembly
[profile.release]
opt-level = 's'
Or, to even more aggressively optimize for size, at further potential speed
costs:
[profile.release]
opt-level = 'z'
Size Profiling
If tweaking build configurations to optimize for code size isn't resulting in
a small enough .wasm binary, it is time to do some profiling to see where
the remaining code size is coming from.
⚡ Just like how we let time profiling guide our speed up efforts, we
want to let size profiling guide our code size shrinking efforts. Fail to
do this and you risk wasting your own time!
https://rustwasm.github.io/docs/book/print.html 81/97
1/15/25, 10:07 AM Rust and WebAssembly
Then, you can use find to locate the .ll file containing the LLVM-IR in
cargo 's target directory:
References
https://rustwasm.github.io/docs/book/print.html 83/97
1/15/25, 10:07 AM Rust and WebAssembly
Avoid Panicking
This is definitely easier said than done, but tools like twiggy and
manually inspecting LLVM-IR can help you figure out which functions are
panicking.
Panics do not always appear as a panic!() macro invocation. They arise
implicitly from many constructs, such as:
Indexing a slice panics on out of bounds indices: my_slice[i]
The first two can be translated into the third. Indexing can be replaced
with fallible my_slice.get(i) operations. Division can be replaced with
checked_div calls. Now we only have a single case to contend with.
#[inline]
pub fn unwrap_abort<T>(o: Option<T>) -> T {
use std::process;
match o {
Some(t) => t,
None => process::abort(),
}
}
want to use this unsafe approach when you 110% know that the
assumption holds, and the compiler just isn't smart enough to see it. Even
if you go down this route, you should have a debug build configuration
that still does the checking, and only use unchecked operations in release
builds.
Then rustc and LLVM will create a new copy of the function for each T
type that the function is used with. This presents many opportunities for
compiler optimizations based on which particular T each copy is working
with, but these copies add up quickly in terms of code size.
If you use trait objects instead of type parameters, like this:
https://rustwasm.github.io/docs/book/print.html 85/97
1/15/25, 10:07 AM Rust and WebAssembly
Then dynamic dispatch via virtual calls is used, and only a single version
of the function is emitted in the .wasm . The downside is the loss of the
compiler optimization opportunities and the added cost of indirect,
dynamically dispatched function calls.
JavaScript Interoperation
https://rustwasm.github.io/docs/book/print.html 86/97
1/15/25, 10:07 AM Rust and WebAssembly
Because of wasm's limited value types, these functions must operate only
on primitive numeric types.
Custom Sections
Custom sections allow embedding named arbitrary data into a wasm
module. The section data is set at compile time and is read directly from
the wasm module, it cannot be modified at runtime.
In Rust, custom sections are static arrays ( [T; size] ) exposed with the
#[link_section] attribute:
#[link_section = "hello"]
pub static SECTION: [u8; 24] = *b"This is a custom section";
This adds a custom section named hello to the wasm file, the rust
variable name SECTION is arbitrary, changing it wouldn't alter the
behaviour. The contents are bytes of text here but could be any arbitrary
data.
https://rustwasm.github.io/docs/book/print.html 88/97
1/15/25, 10:07 AM Rust and WebAssembly
WebAssembly.compileStreaming(fetch("sections.wasm"))
.then(mod => {
const sections = WebAssembly.Module.customSections(mod, "hello");
since clang is shipping their wasm32 target by default now, but the story
isn't quite there yet.
File I/O
WebAssembly does not have access to a file system, so crates that
assume the existence of a file system — and don't have wasm-specific
workarounds — will not work.
Spawning Threads
There are plans to add threading to WebAssembly, but it isn't shipping
yet. Attempts to spawn on a thread on the wasm32-unknown-unknown target
will panic, which triggers a wasm trap.
#![no_std]
Crates that do not rely on the standard library tend to work well with
WebAssembly.
https://rustwasm.github.io/docs/book/print.html 90/97
1/15/25, 10:07 AM Rust and WebAssembly
Parsers
Parsers — so long as they just take input and don't perform their own I/O
— tend to work well with WebAssembly.
Text Processing
Crates that deal with the complexities of human language when
expressed in textual form tend to work well with WebAssembly.
Rust Patterns
Shared solutions for particular situations specific to programming in Rust
tend to work well with WebAssembly.
https://rustwasm.github.io/docs/book/print.html 91/97
1/15/25, 10:07 AM Rust and WebAssembly
If that command fails, then your crate doesn't support WebAssembly right
now. If it doesn't fail, then your crate might support WebAssembly. You
can be 100% sure that it does (and continues to do so!) by adding tests for
wasm and running those tests in CI.
use std::fs;
use std::path::Path;
Into this:
https://rustwasm.github.io/docs/book/print.html 92/97
1/15/25, 10:07 AM Rust and WebAssembly
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
web-sys = "0.3"
You can also define a trait and implement it for WebAssembly and the
Web and also for native targets:
https://rustwasm.github.io/docs/book/print.html 93/97
1/15/25, 10:07 AM Rust and WebAssembly
trait ReadMyThing {
type F: Future<Item = MyThing>;
fn read(&self) -> Self::F;
}
#[cfg(target_arch = "wasm32")]
struct WebReadMyThing {
// ...
}
#[cfg(target_arch = "wasm32")]
impl ReadMyThing for WebReadMyThing {
// ...
}
#[cfg(not(target_arch = "wasm32"))]
struct NativeReadMyThing {
// ...
}
#[cfg(not(target_arch = "wasm32"))]
impl ReadMyThing for NativeReadMyThing {
// ...
}
https://rustwasm.github.io/docs/book/print.html 94/97
1/15/25, 10:07 AM Rust and WebAssembly
#![cfg(target_arch = "wasm32")]
fn do_work() {
// Do work with only this thread...
}
#![cfg(not(target_arch = "wasm32"))]
fn do_work() {
use std::thread;
Another option is to factor out thread spawning from your library and
allow users to "bring their own threads" similar to factoring out file I/O
and allowing users to bring their own I/O. This has the side effect of
playing nice with applications that want to own their own custom thread
pool.
For example, you can add this to your .travis.yml configuration for
Travis CI:
https://rustwasm.github.io/docs/book/print.html 95/97
1/15/25, 10:07 AM Rust and WebAssembly
matrix:
include:
- language: rust
rust: stable
name: "check wasm32 support"
install: rustup target add wasm32-unknown-unknown
script: cargo check --target wasm32-unknown-unknown
and instantiation with network transfer (or make sure your bundler is
able to use that function). However, instantiateStreaming requires that
the HTTP response has the application/wasm MIME type set, or else it will
throw an error.
How to configure MIME types for the Apache HTTP server
How to configure MIME types for the NGINX HTTP server
More Resources
Best Practices for Webpack in Production. Many Rust and
WebAssembly projects use Webpack to bundle their Rust-generated
WebAssembly, JavaScript, CSS, and HTML. This guide has tips for
getting the most out of Webpack when deploying to production
environments.
Apache documentation. Apache is a popular HTTP server for use in
production.
NGINX documentation. NGINX is a popular HTTP server for use in
production.
https://rustwasm.github.io/docs/book/print.html 97/97