+ - 0:00:00
Notes for current slide
Notes for next slide

Hello wasm-bindgen!

Rust generated bindings between JS and WebAssembly


rustwasmjs

Ashley Williams, @ag_dubs

1 / 83

crabshly

2 / 83

wasmwg

3 / 83

repo

4 / 83

german village

5 / 83

wasm spa

6 / 83

wasm-bindgen

Facilitating high-level interactions between wasm modules and JavaScript

7 / 83

wasm-bindgen

Facilitating high-level interactions between wasm modules and JavaScript

What?

8 / 83

wasm-bindgen

Facilitating high-level interactions between wasm modules and JavaScript

What?

Why?

9 / 83

wasm-bindgen

Facilitating high-level interactions between wasm modules and JavaScript

What?

Why?

How?

10 / 83
  • What does wasm-bindgen do

  • WebAssembly: An Overview

  • Developer Workflow

  • wasm-bindgen Features

  • How does wasm-bindgen even

11 / 83

WHAT

does wasm-bindgen do

12 / 83

Create a wrapper JS module for the wasm code


Generate bindings for JS to communicate with wasm code

13 / 83

wasm-bindgen is an unusual bindgen

14 / 83

wasm-bindgen is an unusual bindgen


... it generates bindings for 2 things to communicate

15 / 83

wasm-bindgen is an unusual bindgen


... it generates bindings for 2 things to communicate


but neither of those things is Rust!

16 / 83

wasm-bindgen generates JavaScript!

17 / 83

wasm-bindgen generates JavaScript!


...but why?

18 / 83

WHY

does wasm-bindgen

19 / 83

WebAssembly:

An Overview

20 / 83

webassembly logo

WebAssembly (abbreviated wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

21 / 83
(module
(func $addTwo (param i32 i32) (result i32)
(i32.add
(get_local 0)
(get_local 1)))
(export "addTwo" $addTwo))

wasm

22 / 83

shrug

Why wasm

  • Size- and load-time-efficient binary format

  • Native speed by using hardware capabilities

  • Memory Safe sandboxed execution environment

  • Part of the Open Web Platform

23 / 83

cargo build target wasm

Why Rust and wasm?

  • Rust has no garbage collection or runtime

  • All the other awesome things about Rust

24 / 83

hearteyes nerd stareyes

The Rust Community is HYPE About WebAssembly

25 / 83

module counts

26 / 83

alert

Wasm modules can only call/export functions that deal exclusively with i32, i64, f32, and f64.

27 / 83

nerd

28 / 83

no

29 / 83

ferris

The goal of wasm-bindgen is to enhance the "ABI" of wasm modules with richer types.

30 / 83

Application Binary Interface (ABI)

An interface between two binary program modules; often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.

31 / 83

wasm is the ABI of the Web...

32 / 83

wasm is the ABI of the Web...

it's just not complete yet.

33 / 83

wasm to runtime

34 / 83

wasm to runtime plus js

35 / 83

wasmbindgenfull

36 / 83

Productivity!


Maintainability!


Accessibility!

37 / 83

HOW

38 / 83

magic

39 / 83

cry at computer

Developer Workflow

40 / 83

awesome synchronized dance

Developer Workflow

41 / 83

rust loves js

wasm is not trying to replace JavaScript

42 / 83

wasmbindgenfull

43 / 83

doctor

Use wasm to surgically replace hotpaths in JavaScript

44 / 83

oxidizing source maps

45 / 83

scalajs map benchmark

46 / 83

HOW?!

47 / 83

workflow

48 / 83
//Cargo.toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
// lib.rs
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
49 / 83

cargo install wasm-pack


demo of wasm-pack

50 / 83

wasm-pack publish


hello npm

51 / 83
{
"scripts": {
"start": "webpack-dev-server"
},
"dependencies": {
"hello-wasm": "^6.6.6"
},
"devDependencies": {
"webpack": "^4.0.1",
"webpack-cli": "^2.0.10",
"webpack-dev-server": "^3.1.0"
}
}
hello alert
52 / 83

surprise gift sparkles

You shouldn't even have to know that you are using wasm

53 / 83

WHAT

just happened

54 / 83

files

55 / 83

how it works

56 / 83

#[wasm_bindgen] attribute


Marks the interface touch points

  • Import JS Classes/Functions

  • Export Rust Classes/Functions

57 / 83

The wasm-bindgen CLI


Use the attributes to generate JS bindings!

58 / 83

WHAT

can I do

59 / 83

Constructors

Rust Instantiating a JS Class

#[wasm_bindgen]
extern {
type Shoes;
#[wasm_bindgen(constructor)]
fn new() -> Shoes;
}
// Become a cobbler; construct new Shoes()
let shoes = Shoes::new();
60 / 83

Constructors

JS Instantiating a Rust Class

#[wasm_bindgen]
pub struct Foo {
contents: u32,
}
#[wasm_bindgen]
impl Foo {
#[wasm_bindgen(constructor)]
pub fn new() -> Foo {
Foo { contents: 0 }
}
pub fn get_contents(&self) -> u32 {
self.contents
}
}
61 / 83

Constructors

JS Instantiating a Rust Class

import { Foo } from './my_module';
const f = new Foo();
console.log(f.get_contents());
62 / 83

Methods

Rust using JS Classes' Methods

#[wasm_bindgen]
extern {
type Set;
#[wasm_bindgen(method)]
fn has(this: &Set, element: &JsValue) -> bool;
}
let set: Set = ...;
let elem: JsValue = ...;
if set.has(&elem) {
...
}
63 / 83

Class Heirarchy

Rust understands JS extends

#[wasm_bindgen]
extern {
type Foo;
#[wasm_bindgen(extends = Foo)]
type Bar;
}
let x: &Bar = ...;
let y: &Foo = x.as_ref(); // zero cost cast
impl From<Bar> for Foo { ... }
impl AsRef<Foo> for Bar { ... }
impl AsMut<Foo> for Bar { ... }
64 / 83

Class Heirarchy

Rust understands JS extends

#[wasm_bindgen]
extern {
type Foo;
#[wasm_bindgen(extends = Foo)]
type Bar;
#[wasm_bindgen(extends = Foo, extends = Bar)]
type Baz;
}
let x: &Baz = ...;
let y1: &Bar = x.as_ref();
let y2: &Foo = x.as_ref();
65 / 83

inheritence

66 / 83

js-sys and web-sys

67 / 83

js-sys

Provide raw bindings to all the global APIs guaranteed to exist in every JavaScript environment by the ECMAScript standard without writing the #[wasm_bindgen] imports by hand.

extern crate js_sys;
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn timed(callback: &js_sys::Function) -> f64 {
let then = js_sys::Date::now();
callback.apply(JsValue::null(), &js_sys::Array::new()).unwrap();
let now = js_sys::Date::now();
now - then
}
68 / 83

web-sys

The web-sys crate provides raw bindings to all of the Web's APIs, and its source lives at wasm-bindgen/crates/web-sys.

The web-sys crate is entirely mechanically generated inside build.rs using wasm-bindgen's WebIDL frontend and the WebIDL interface definitions for Web APIs.


Web Interface Definition Language

https://heycam.github.io/webidl/

69 / 83

HOW

does wasm-bindgen even

70 / 83

look inside

71 / 83

Design Principles

  • ES6 Modules

  • Unintrusive

72 / 83

How we shoehorn JS objects into a u32 for wasm to use?


tight fit

73 / 83

JS Objects in Rust

pub struct JsValue {
idx: u32,
}
// "private" constructors
impl Drop for JsValue {
fn drop(&mut self) {
unsafe {
__wbindgen_object_drop_ref(self.idx);
}
}
}
74 / 83

Temporary JS Objects: Stack

// foo.rs
#[wasm_bindgen]
pub fn foo(a: &JsValue) {
// ...
}

Here we're using the special JsValue type from the wasm-bindgen library itself. Our exported function, foo, takes a reference to an object. This notably means that it can't persist the object past the lifetime of this function call.

Now what we actually want to generate is a JS module that looks like (in Typescript parlance):

// foo.d.ts
export function foo(a: any);
75 / 83

Temporary JS Objects: Stack

// foo.js
import * as wasm from './foo_bg';
const stack = [];
function addBorrowedObject(obj) {
stack.push(obj);
return stack.length - 1;
}
export function foo(arg0) {
const idx0 = addBorrowedObject(arg0);
try {
wasm.foo(idx0);
} finally {
stack.pop();
}
}
76 / 83

Temporary JS Objects: Stack

// what the user wrote
pub fn foo(a: &JsValue) {
// ...
}
// what got gen'd
#[export_name = "foo"]
pub extern fn __wasm_bindgen_generated_foo(arg0: u32) {
let arg0 = unsafe {
ManuallyDrop::new(JsValue::__from_idx(arg0))
};
let arg0 = &*arg0;
foo(arg0);
}
77 / 83

stressed

78 / 83

The best part about wasm-bindgen is that you don't have to worry about how it works.

79 / 83

The best part about wasm-bindgen is that you don't have to worry about how it works.



It just does.

80 / 83

Learn More!

The wasm-bindgen Guide

81 / 83

Get Involved!

The RustWasm Working Group

82 / 83

Thanks!

@ag_dubs | bit.ly/hello-wasm-bindgen

83 / 83

crabshly

2 / 83
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow