diff --git a/chapters/en-US/wasm.chapter b/chapters/en-US/wasm.chapter new file mode 100644 index 0000000..c1ea8f5 --- /dev/null +++ b/chapters/en-US/wasm.chapter @@ -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` + +
+ +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: + +
+ +--- + +## Installing: `rustup` Target + +`rustup` allows installing multiple compilation targets. + +
+ +--- + +# Standalone Executable + +--- + +## Standalone Executable + +
+ +
+ +--- + +## Standalone Executable + +
+ +This will create a directory structure like so: + +
+ +--- + +## 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. + +
+ +--- + +## Standalone Executable + +Create `site/index.html`: + +
+ +--- + +## Standalone Executable + +Running `python -m SimpleHTTPServer` or equivalent, browsing to `localhost:8000/site`, and opening the console yield the following output: + +
+ +--- + +# 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: + +
+ +--- + +## Rust from JS + +
+ +
+ +--- + +## Rust from JS + +We can use the same Makefile as before. + +
+ +--- + +## Rust from JS + +The `onRuntimeInitialized` hook for `Module` defines what is called after the WebAssembly is loaded. + +
+ +--- + +## Rust from JS + +Running `python -m SimpleHTTPServer` or equivalent, browsing to `localhost:8000/site`, and opening the console yield the following output: + +
+ +--- + +# 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: + +
+ +--- + +## JS from Rust + +Calling the Javascript function: + +
+ +--- + +## DOM Interaction + +There is a [WebPlatform crate](https://github.com/tcr/rust-webplatform) to explore and contribute to. + +
+ +--- + +## 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! \ No newline at end of file diff --git a/chapters/shared/code/wasm/1.bash b/chapters/shared/code/wasm/1.bash new file mode 100644 index 0000000..02a9472 --- /dev/null +++ b/chapters/shared/code/wasm/1.bash @@ -0,0 +1,4 @@ +./emsdk update +./emsdk install sdk-incoming-64bit +./emsdk activate sdk-incoming-64bit +source ./emsdk_env.sh \ No newline at end of file diff --git a/chapters/shared/code/wasm/10.output b/chapters/shared/code/wasm/10.output new file mode 100644 index 0000000..319e64a --- /dev/null +++ b/chapters/shared/code/wasm/10.output @@ -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 \ No newline at end of file diff --git a/chapters/shared/code/wasm/11.bash b/chapters/shared/code/wasm/11.bash new file mode 100644 index 0000000..dce3cdd --- /dev/null +++ b/chapters/shared/code/wasm/11.bash @@ -0,0 +1,2 @@ +rustup override set nightly +rustup target add wasm32-unknown-emscripten \ No newline at end of file diff --git a/chapters/shared/code/wasm/12.bash b/chapters/shared/code/wasm/12.bash new file mode 100644 index 0000000..7ecb9dc --- /dev/null +++ b/chapters/shared/code/wasm/12.bash @@ -0,0 +1 @@ +cargo init wasm-demo --bin \ No newline at end of file diff --git a/chapters/shared/code/wasm/13.rs b/chapters/shared/code/wasm/13.rs new file mode 100644 index 0000000..41c0f91 --- /dev/null +++ b/chapters/shared/code/wasm/13.rs @@ -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::>(); + + CString::new(descriptions.join(", ")) + .unwrap() + .into_raw() +} + +fn main() { + // Deliberately blank. +} \ No newline at end of file diff --git a/chapters/shared/code/wasm/14.html b/chapters/shared/code/wasm/14.html new file mode 100644 index 0000000..c6aab5b --- /dev/null +++ b/chapters/shared/code/wasm/14.html @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/chapters/shared/code/wasm/15.output b/chapters/shared/code/wasm/15.output new file mode 100644 index 0000000..9189911 --- /dev/null +++ b/chapters/shared/code/wasm/15.output @@ -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 \ No newline at end of file diff --git a/chapters/shared/code/wasm/17.js b/chapters/shared/code/wasm/17.js new file mode 100644 index 0000000..b08d359 --- /dev/null +++ b/chapters/shared/code/wasm/17.js @@ -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); \ No newline at end of file diff --git a/chapters/shared/code/wasm/18.rs b/chapters/shared/code/wasm/18.rs new file mode 100644 index 0000000..51f04a5 --- /dev/null +++ b/chapters/shared/code/wasm/18.rs @@ -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); +} \ No newline at end of file diff --git a/chapters/shared/code/wasm/19.rs b/chapters/shared/code/wasm/19.rs new file mode 100644 index 0000000..14330dc --- /dev/null +++ b/chapters/shared/code/wasm/19.rs @@ -0,0 +1,24 @@ +extern crate webplatform; + +fn main() { + let document = webplatform::init(); + let body = document.element_query("body") + .unwrap(); + body.html_append("\ +

This header brought to you by Rust

\ + \ + "); + + let button = document.element_query("button") + .unwrap(); + button.on("mouseenter", move |_| { + println!("Mouse entered!"); + body.html_append("

Mouse entered!

"); + }); + button.on("click", |_| { + println!("Clicked!"); + webplatform::alert("Clicked!"); + }); + + webplatform::spin(); +} \ No newline at end of file diff --git a/chapters/shared/code/wasm/2.bash b/chapters/shared/code/wasm/2.bash new file mode 100644 index 0000000..0fe9148 --- /dev/null +++ b/chapters/shared/code/wasm/2.bash @@ -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) \ No newline at end of file diff --git a/chapters/shared/code/wasm/3.bash b/chapters/shared/code/wasm/3.bash new file mode 100644 index 0000000..a1f8f35 --- /dev/null +++ b/chapters/shared/code/wasm/3.bash @@ -0,0 +1 @@ +rustup target add wasm32-unknown-emscripten \ No newline at end of file diff --git a/chapters/shared/code/wasm/4.bash b/chapters/shared/code/wasm/4.bash new file mode 100644 index 0000000..7ecb9dc --- /dev/null +++ b/chapters/shared/code/wasm/4.bash @@ -0,0 +1 @@ +cargo init wasm-demo --bin \ No newline at end of file diff --git a/chapters/shared/code/wasm/5.rs b/chapters/shared/code/wasm/5.rs new file mode 100644 index 0000000..2e957ca --- /dev/null +++ b/chapters/shared/code/wasm/5.rs @@ -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); +} \ No newline at end of file diff --git a/chapters/shared/code/wasm/6.bash b/chapters/shared/code/wasm/6.bash new file mode 100644 index 0000000..928a50c --- /dev/null +++ b/chapters/shared/code/wasm/6.bash @@ -0,0 +1 @@ +cargo build --target=wasm32-unknown-emscripten --release \ No newline at end of file diff --git a/chapters/shared/code/wasm/7.output b/chapters/shared/code/wasm/7.output new file mode 100644 index 0000000..473eeae --- /dev/null +++ b/chapters/shared/code/wasm/7.output @@ -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 \ No newline at end of file diff --git a/chapters/shared/code/wasm/8.makefile b/chapters/shared/code/wasm/8.makefile new file mode 100644 index 0000000..3585ffa --- /dev/null +++ b/chapters/shared/code/wasm/8.makefile @@ -0,0 +1,6 @@ +SHELL := /bin/bash + +all: + cargo build --target=wasm32-unknown-emscripten --release + cp target/wasm32-unknown-emscripten/release/deps/*.wasm site/site.wasm + cp target/wasm32-unknown-emscripten/release/deps/*[!.asm].js site/site.js \ No newline at end of file diff --git a/chapters/shared/code/wasm/9.html b/chapters/shared/code/wasm/9.html new file mode 100644 index 0000000..4a3d444 --- /dev/null +++ b/chapters/shared/code/wasm/9.html @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/toc/english.html b/toc/english.html index 64342c2..a0da172 100644 --- a/toc/english.html +++ b/toc/english.html @@ -83,6 +83,7 @@

Unfinished

diff --git a/toc/english.md b/toc/english.md index 496fd23..4554f2b 100644 --- a/toc/english.md +++ b/toc/english.md @@ -74,4 +74,5 @@ * [Standard types](../index.html?chapter=standard-types&locale=en-US) * [Outlook](../index.html?chapter=outlook&locale=en-US) +* [WebAssembly](../index.html?chapter=wasm&locale=en-US) * [Inner Mutability](../index.html?chapter=inner-mutability&locale=en-US)