Skip to content
This repository has been archived by the owner on Mar 23, 2020. It is now read-only.

Commit

Permalink
WebAssembly chapter in english (#51)
Browse files Browse the repository at this point in the history
* WebAssembly chapter in english

* Speeling
  • Loading branch information
Andrew Hobden authored May 16, 2017
1 parent e525e83 commit df95695
Show file tree
Hide file tree
Showing 21 changed files with 382 additions and 0 deletions.
198 changes: 198 additions & 0 deletions presentation/chapters/en-US/wasm.chapter
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# WebAssembly
[Table of Contents](toc/english.html)

---

## What?

WebAssembly enables running Rust (among others) in Javascript environments like the web browser.

It is the successor to asm.js in many ways.

It is currently a developing standard and is often not enabled by default.

---

## Gotcha

WebAssembly is still not widely supported and has a number of rough edges.

---

## Installing

Setup is a bit unrefined at this moment, but it should improve in the future.

* Fetch `emsdk` from [emscripten](http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html).
* Unpack it somewhere sensible.
* Navigate to the directory in your terminal.

---

## Installing: `emcc`

<pre><code data-source="chapters/shared/code/wasm/1.bash" data-trim="hljs bash"></code></pre>

The output of the third command will offer instructions for what to add to `$PATH` if desired.

> We use `incoming` to utilize the latest refinements.

---

## Installing: `emcc`

The versions of the toolchain are quite important. Verify there are no errors running the following:

<pre><code data-source="chapters/shared/code/wasm/2.bash" data-trim="hljs bash"></code></pre>

---

## Installing: `rustup` Target

`rustup` allows installing multiple compilation targets.

<pre><code data-source="chapters/shared/code/wasm/3.bash" data-trim="hljs bash"></code></pre>

---

# Standalone Executable

---

## Standalone Executable

<pre><code data-source="chapters/shared/code/wasm/4.bash" data-trim="hljs bash"></code></pre>

<pre><code data-source="chapters/shared/code/wasm/5.rs" data-trim="hljs rust"></code></pre>

---

## Standalone Executable

<pre><code data-source="chapters/shared/code/wasm/6.bash" data-trim="hljs bash"></code></pre>

This will create a directory structure like so:

<pre><code data-source="chapters/shared/code/wasm/7.output" data-trim="hljs bash"></code></pre>

---

## Standalone Executable

Once we generate the `wasm` and `js` we want to place them in with a `site` folder. We can use a `Makefile` for this.

<pre><code data-source="chapters/shared/code/wasm/8.makefile" data-trim="hljs makefile"></code></pre>

---

## Standalone Executable

Create `site/index.html`:

<pre><code data-source="chapters/shared/code/wasm/9.html" data-trim="hljs html"></code></pre>

---

## Standalone Executable

Running `python -m SimpleHTTPServer` or equivalent, browsing to `localhost:8000/site`, and opening the console yield the following output:

<pre><code data-source="chapters/shared/code/wasm/10.output" data-trim="hljs bash"></code></pre>

---

# Rust from JS

---

## Rust from JS

Exporting functions for use in Javascript is a bit more complicated.

Additionally, interactions must be handled like interactions to C.

---

## Rust from JS

The nightly channel is currently necessary to get this to work properly:

<pre><code data-source="chapters/shared/code/wasm/11.bash" data-trim="hljs bash"></code></pre>

---

## Rust from JS

<pre><code data-source="chapters/shared/code/wasm/12.bash" data-trim="hljs bash"></code></pre>

<pre><code data-source="chapters/shared/code/wasm/13.rs" data-trim="hljs rust"></code></pre>

---

## Rust from JS

We can use the same Makefile as before.

<pre><code data-source="chapters/shared/code/wasm/8.makefile" data-trim="hljs makefile"></code></pre>

---

## Rust from JS

The `onRuntimeInitialized` hook for `Module` defines what is called after the WebAssembly is loaded.

<pre><code data-source="chapters/shared/code/wasm/14.html" data-trim="hljs html"></code></pre>

---

## Rust from JS

Running `python -m SimpleHTTPServer` or equivalent, browsing to `localhost:8000/site`, and opening the console yield the following output:

<pre><code data-source="chapters/shared/code/wasm/15.output" data-trim="hljs bash"></code></pre>

---

# JS from Rust

---

## JS from Rust

Calling JS code from Rust has similar complications.

It is done primarily through passing the `--js-library` flag at link time, which requires the nightly channel of rust.

Passing numerics is relatively simple, but passing more complex things like strings requires extra effort.

---

## JS from Rust

Returning a string for Rust code:

<pre><code data-source="chapters/shared/code/wasm/17.js" data-trim="hljs javascript"></code></pre>

---

## JS from Rust

Calling the Javascript function:

<pre><code data-source="chapters/shared/code/wasm/18.rs" data-trim="hljs rust"></code></pre>

---

## DOM Interaction

There is a [WebPlatform crate](https://github.com/tcr/rust-webplatform) to explore and contribute to.

<pre><code data-source="chapters/shared/code/wasm/19.rs" data-trim="hljs rust"></code></pre>

---

## Future

WebAssembly is rapidly becoming more refined and mature. Rust's integration is also under active work.

Keep your eyes peeled for more, better support!
4 changes: 4 additions & 0 deletions presentation/chapters/shared/code/wasm/1.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
./emsdk update
./emsdk install sdk-incoming-64bit
./emsdk activate sdk-incoming-64bit
source ./emsdk_env.sh
7 changes: 7 additions & 0 deletions presentation/chapters/shared/code/wasm/10.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
trying binaryen method: native-wasm
asynchronously preparing wasm
binaryen method succeeded.
run() called, but dependencies remain, so not running
pre-main prep time: 108 ms
South
false
2 changes: 2 additions & 0 deletions presentation/chapters/shared/code/wasm/11.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rustup override set nightly
rustup target add wasm32-unknown-emscripten
1 change: 1 addition & 0 deletions presentation/chapters/shared/code/wasm/12.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo init wasm-demo --bin
23 changes: 23 additions & 0 deletions presentation/chapters/shared/code/wasm/13.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::os::raw::c_char;
use std::ffi::CString;
use std::collections::HashMap;

#[no_mangle]
pub fn get_data() -> *mut c_char {
let mut data = HashMap::new();
data.insert("Alice", "send");
data.insert("Bob", "receive");
data.insert("Carol", "intercept");

let descriptions = data.iter()
.map(|(p,a)| format!("{} likes to {} messages", p, a))
.collect::<Vec<_>>();

CString::new(descriptions.join(", "))
.unwrap()
.into_raw()
}

fn main() {
// Deliberately blank.
}
17 changes: 17 additions & 0 deletions presentation/chapters/shared/code/wasm/14.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<html>
<head>
<script>
// This is read and used by `site.js`
var Module = {
wasmBinaryFile: "site.wasm",
onRuntimeInitialized: main,
}
function main() {
let get_data = Module.cwrap('get_data', 'string', []);
console.log(get_data());
}
</script>
<script src="site.js"></script>
</head>
<body></body>
</html>
4 changes: 4 additions & 0 deletions presentation/chapters/shared/code/wasm/15.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
trying binaryen method: native-wasm
asynchronously preparing wasm
binaryen method succeeded.
Bob likes to receive messages, Alice likes to send messages, Carol likes to intercept messages
17 changes: 17 additions & 0 deletions presentation/chapters/shared/code/wasm/17.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

var library = {
get_data: function() {
var str = "Hello from JS.";
alert(str);

// Not needed for numerics.
var len = lengthBytesUTF8(str);
var buffer = Module._malloc(len);
Module.stringToUTF8(str, buffer, len);

return buffer;
},
};

mergeInto(LibraryManager.library, library);
26 changes: 26 additions & 0 deletions presentation/chapters/shared/code/wasm/18.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![feature(link_args)]

#[cfg_attr(target_arch="wasm32", link_args = "\
--js-library site/utilities.js\
")]
extern {}

use std::os::raw::c_char;
use std::ffi::CStr;

extern {
fn get_data() -> *mut c_char;
}

fn get_data_safe() -> String {
let data = unsafe {
CStr::from_ptr(get_data())
};
data.to_string_lossy()
.into_owned()
}

fn main() {
let data = get_data_safe();
println!("{:?}", data);
}
24 changes: 24 additions & 0 deletions presentation/chapters/shared/code/wasm/19.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
extern crate webplatform;

fn main() {
let document = webplatform::init();
let body = document.element_query("body")
.unwrap();
body.html_append("\
<h1>This header brought to you by Rust</h1>\
<button>Click me!</button>\
");

let button = document.element_query("button")
.unwrap();
button.on("mouseenter", move |_| {
println!("Mouse entered!");
body.html_append("<p>Mouse entered!</p>");
});
button.on("click", |_| {
println!("Clicked!");
webplatform::alert("Clicked!");
});

webplatform::spin();
}
7 changes: 7 additions & 0 deletions presentation/chapters/shared/code/wasm/2.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.9
clang version 4.0.0 (emscripten 1.37.9 : 1.37.9)
Target: x86_64-apple-darwin16.4.0
Thread model: posix
InstalledDir: /Users/$USER/emsdk/clang/e1.37.9_64bit
INFO:root:(Emscripten: Running sanity checks)
1 change: 1 addition & 0 deletions presentation/chapters/shared/code/wasm/3.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rustup target add wasm32-unknown-emscripten
1 change: 1 addition & 0 deletions presentation/chapters/shared/code/wasm/4.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo init wasm-demo --bin
16 changes: 16 additions & 0 deletions presentation/chapters/shared/code/wasm/5.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#[derive(Debug)]
pub enum Direction { North, South, East, West }

fn is_north(dir: Direction) -> bool {
match dir {
Direction::North => true,
_ => false,
}
}

fn main() {
let points = Direction::South;
println!("{:?}", points);
let compass = is_north(points);
println!("{}", compass);
}
1 change: 1 addition & 0 deletions presentation/chapters/shared/code/wasm/6.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cargo build --target=wasm32-unknown-emscripten --release
13 changes: 13 additions & 0 deletions presentation/chapters/shared/code/wasm/7.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
target
└── wasm32-unknown-emscripten
└── release
├── build
├── deps
│   ├── wasm_demo-9c23ae9a241f12fa.asm.js
│   ├── wasm_demo-9c23ae9a241f12fa.js
│   └── wasm_demo-9c23ae9a241f12fa.wasm
├── examples
├── incremental
├── native
├── wasm-demo.d
└── wasm-demo.js
Loading

0 comments on commit df95695

Please sign in to comment.