class: middle, left # Hello `wasm-bindgen`! .subtitle[Rust generated bindings between JS and WebAssembly]
![rustwasmjs](public/img/rustwasmjs.png) #### Ashley Williams, [@ag_dubs](https://twitter.com/ag_dubs) --- class: middle, center .small[![crabshly](public/img/crabshly.jpg)] --- class: middle, center .small[![wasmwg](public/img/wasmwg.png)] --- class: middle, center ![repo](public/img/repo.png) --- class: middle, center ![german village](public/img/germanvillage.png) --- class: middle, center ![wasm spa](public/img/relaxingspa.png) --- class: middle, center # `wasm-bindgen` .subtitle[Facilitating high-level interactions between wasm modules and JavaScript] -- ## What? -- ## Why? -- ## How? --- class: middle, left - ## What does `wasm-bindgen` do - ## WebAssembly: An Overview - ## Developer Workflow - ## `wasm-bindgen` Features - ## How does `wasm-bindgen` even --- class: middle, center # .big[WHAT] # does `wasm-bindgen` do --- class: middle, center ## Create a wrapper JS module for the wasm code
## Generate bindings for JS to communicate with wasm code --- class: middle, center # `wasm-bindgen` is an unusual bindgen -- ## ... it generates bindings for 2 things to communicate -- # but neither of those things is Rust! --- class: middle, center # `wasm-bindgen` generates JavaScript! -- # ...but why? --- class: middle, center # .big[WHY] # does `wasm-bindgen` --- class: middle, center # WebAssembly: # An Overview --- class: middle, center .tiny[![webassembly logo](public/img/wasmlogo.png)] ### **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. --- class: middle, left ``` (module (func $addTwo (param i32 i32) (result i32) (i32.add (get_local 0) (get_local 1))) (export "addTwo" $addTwo)) ``` ![wasm](public/img/wasm.png) --- class: middle, left .center[ .tiny[![shrug](public/img/shrug.png)] # 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 --- class: middle, left .center[ ![cargo build target wasm](public/img/cargobuildtargetwasm.png) # Why Rust and `wasm`? ] - ### Rust has no garbage collection or runtime - ### All the other awesome things about Rust --- class: middle, center .tiny[![hearteyes](public/img/hearteyes.png)] .tiny[![nerd](public/img/nerd.png)] .tiny[![stareyes](public/img/stareyes.png)] # The Rust Community is HYPE About WebAssembly --- class: middle, center ![module counts](public/img/modulecounts.png) --- class: middle, center .tiny[![alert](public/img/alert.png)] # Wasm modules can only call/export functions that deal exclusively with `i32`, `i64`, `f32`, and `f64`. --- class: middle, center ![nerd](public/img/nerd.gif) --- class: middle, center ![no](public/img/no.gif) --- class: middle, center .small[![ferris](public/img/wasm-ferris.png)] # The goal of wasm-bindgen is to enhance the "ABI" of wasm modules with richer types. --- class: middle, center # 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. --- class: middle, center # `wasm` is the ABI of the Web... -- # it's just not complete yet. --- class: middle, center ![wasm to runtime](public/img/wasmtoruntime.png) --- class: middle, center ![wasm to runtime plus js](public/img/wasmtoruntimeplusjs.png) --- class: middle, center ![wasmbindgenfull](public/img/wasmbindgenfull.png) --- class: middle, center # Productivity!
# Maintainability!
# Accessibility! --- class: middle, center # .big[HOW] --- class: middle, center ![magic](public/img/magic.gif) --- class: middle, center ![cry at computer](public/img/developerexperience.gif) # Developer Workflow --- class: middle, center ![awesome synchronized dance](public/img/developerexperience2.gif) # Developer Workflow --- class: middle, center ![rust loves js](public/img/lin_rustjs.png) # `wasm` is not trying to replace JavaScript --- class: middle, center ![wasmbindgenfull](public/img/wasmbindgenfull.png) --- class: middle, center .tiny[![doctor](public/img/doctor.png)] # Use `wasm` to surgically replace hotpaths in JavaScript --- class: middle, center ![oxidizing source maps](public/img/oxidizingsourcemaps.png) --- class: middle, center .medium[![scalajs map benchmark](public/img/scalajssourcebench.png)] --- class: middle, center # .big[HOW?!] --- class: middle, center ![workflow](public/img/lin_pipeline.png) --- class: middle, left ```rust //Cargo.toml [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2" ``` ```rust // 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)); } ``` --- class: middle, center # `cargo install wasm-pack`
![demo of wasm-pack](public/img/demo.gif) --- class: middle, center # `wasm-pack publish`
![hello npm](public/img/hellonpm.png) --- class: middle, left ```json { "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" } } ``` .center[ ![hello alert](public/img/helloalert.png) ] --- class: middle, center .tiny[![surprise](public/img/surprise.png)] .tiny[![gift](public/img/gift.png)] .tiny[![sparkles](public/img/sparkles.png)] # You shouldn't even have to know that you are using `wasm` --- class: middle, center # .big[WHAT] # just happened --- class: middle, center ![files](public/img/files.png) --- class: middle, center ![how it works](public/img/howitworks.png) --- class: middle, left # `#[wasm_bindgen]` attribute
## Marks the interface touch points - ### Import JS Classes/Functions - ### Export Rust Classes/Functions --- class: middle, left # The `wasm-bindgen` CLI
## Use the attributes to generate JS bindings! --- class: middle, center # .big[WHAT] # can I do --- class: middle, left # Constructors ### Rust Instantiating a JS Class ```rust #[wasm_bindgen] extern { type Shoes; #[wasm_bindgen(constructor)] fn new() -> Shoes; } ``` ```rust // Become a cobbler; construct `new Shoes()` let shoes = Shoes::new(); ``` --- class: middle, left # Constructors ### JS Instantiating a Rust Class ```rust #[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 } } ``` --- class: middle, left # Constructors ### JS Instantiating a Rust Class ```js import { Foo } from './my_module'; const f = new Foo(); console.log(f.get_contents()); ``` --- class: middle, left # Methods ## Rust using JS Classes' Methods ```rust #[wasm_bindgen] extern { type Set; #[wasm_bindgen(method)] fn has(this: &Set, element: &JsValue) -> bool; } ``` ```rust let set: Set = ...; let elem: JsValue = ...; if set.has(&elem) { ... } ``` --- class: middle, left # Class Heirarchy ## Rust understands JS `extends` ```rust #[wasm_bindgen] extern { type Foo; #[wasm_bindgen(extends = Foo)] type Bar; } let x: &Bar = ...; let y: &Foo = x.as_ref(); // zero cost cast ``` ```rust impl From
for Foo { ... } impl AsRef
for Bar { ... } impl AsMut
for Bar { ... } ``` --- class: middle, left # Class Heirarchy ## Rust understands JS `extends` ```rust #[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(); ``` --- class: middle, center ![inheritence](public/img/inheritence.png) --- class: middle, center # `js-sys` and `web-sys` --- class: middle, left # `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. ```rust 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 } ``` --- class: middle, left # `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.
.center[ ## Web Interface Definition Language https://heycam.github.io/webidl/ ] --- class: middle, center # .big[HOW] # does `wasm-bindgen` even --- class: middle, center ![look inside](public/img/box.gif) --- class: middle, left # Design Principles - ## ES6 Modules - ## Unintrusive --- class: middle, center ## How we shoehorn JS objects into a `u32` for `wasm` to use?
![tight fit](public/img/tightfit.gif) --- class: middle, left # .center[JS Objects in Rust] ```rust pub struct JsValue { idx: u32, } // "private" constructors impl Drop for JsValue { fn drop(&mut self) { unsafe { __wbindgen_object_drop_ref(self.idx); } } } ``` --- class: middle, left ## Temporary JS Objects: Stack ```rust // 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): ```ts // foo.d.ts export function foo(a: any); ``` --- class: middle, left ## Temporary JS Objects: Stack ```js // 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(); } } ``` --- class: middle, left ## Temporary JS Objects: Stack ```rust // 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); } ``` --- class: middle, center ![stressed](public/img/stressed.gif) --- class: middle, center # The best part about `wasm-bindgen` is that you don't have to worry about how it works. --
# It just does. --- class: middle, center # Learn More! # [The `wasm-bindgen` Guide](https://rustwasm.github.io/wasm-bindgen/introduction.html) --- class: middle, center # Get Involved! # [The RustWasm Working Group](https://github.com/rustwasm/team) --- class: middle, center # Thanks! @ag_dubs | [bit.ly/hello-wasm-bindgen](http://bit.ly/hello-wasm-bindgen)