• Stars
    star
    495
  • Rank 88,974 (Top 2 %)
  • Language
  • Created almost 7 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

WebAssembly and Rust: A Web Love Story

WebAssembly and Rust

~ A Web Love Story ~

 love gif  Rustacean

Before Start

  • Basic knowledge of HTML and JavaScript
  • Enthusiasm for going fast on the web
  • Your favourite browser that supports Web Assembly

You can check out about:config (Firefox) or chrome://flags/ (Chrome) and make sure wasm related things are enabled.

WebAssembly (WASM)

WebAssembly or WASM is a low-level bytecode format for in-browser client-side scripting, evolved from JavaScript. Its initial aim is to support compilation from C and C++, though other source languages such as Rust are also supported.

Initial implementation of WebAssembly support in browsers will be based on the featureset of asm.js.

The asm.js is an intermediate programming language designed to allow computer software written in languages such as C to be run as web applications while maintaining performance characteristics considerably better than standard JavaScript, the typical language used for such applications. Consists of a strict subset of JavaScript, into which code written in statically-typed languages with manual memory management (such as C) is translated by a source-to-source compiler such as Emscripten (based on LLVM).

Performance is improved by limiting language features to those amenable to ahead-of-time optimization and other performance improvements.

Code generation based on asm.js

Calculate the length of a string in C:

size_t strlen(char *ptr) {
  char *curr = ptr;
  while (*curr != 0) {
    curr++;
  }
  return (curr - ptr);
}

Would output the following JS code:

function strlen(ptr) {
  ptr = ptr|0;
  var curr = 0;
  curr = ptr;
  while (MEM8[curr]|0 != 0) {
    curr = (curr + 1)|0;
  }
  return (curr - ptr)|0;
}

Note: Much of performance gain over normal JavaScript is due to 100% type consistency and virtually no garbage collection (memory is manually managed in a large typed array).

In March 2017, the WebAssembly Community Group reached consensus on the initial (MVP) binary format, JavaScript API, and reference interpreter. It defines a WebAssembly binary format.

See the representation of 3 different views of the same source code:

C (Input Source)

int factorial(int n) {
  if (n == 0)
    return 1;
  else
    return n * factorial(n-1);
}

Linear Assembly Bytecode (IR)

Data structure used internally by wasm compiler to represent source code.

get_local 0
i64.eqz
if i64
    i64.const 1
else
    get_local 0
    get_local 0
    i64.const 1
    i64.sub
    call 0
    i64.mul
end

WASM binary encoding

In hexadecimal:

20 00
50
04 7E
42 01
05
20 00
20 00
42 01
7D
10 00
7E
0B

The WASM compiler system internally uses s-expressions - notation for nested list (tree-structured) data, invented for and popularized by the programming language Lisp, which uses them for source code as well as data - for parsing simplicity as well to handle intermediate code.

An example is shown below:

(module
  (type $FUNCSIG$dd (func (param f64) (result f64)))
  (import "global.Math" "exp" (func $exp (param f64) (result f64)))
  (memory 256 256)
  (export "memory" (memory 0))
  (func $doubleExp (param $0 f64) (result f64)
    (f64.mul
      (call $exp
        (get_local $0)
      )
      (f64.const 2)
    )
  )
  (export "doubleExp" (func $doubleExp))
)

Emscripten

Emscripten is an LLVM-based project that compiles C and C++ into highly-optimizable JavaScript in asm.js format. This lets you run C and C++ on the web at near-native speed, without plugins.

Thanks to LLVM, Emscripten and asm.js, code runs at near-native speed.

Rust Language

Rust is a systems programming language sponsored by Mozilla Research, which describes it as a "safe, concurrent, practical language," supporting functional and imperative-procedural paradigms. Rust is syntactically similar to C++, but its designers intend it to provide better memory safety while maintaining performance.

Rust is an open source programming language. Its designers have refined the language through the experiences of writing the Servo web browser layout engine and the Rust compiler.

Featuring: zero-cost abstractions, move semantics, guaranteed memory safety, threads without data races, trait-based generics, pattern matching, type inference, minimal runtime and efficient C bindings.

Some code in Rust:

fn main() {
    let greetings = ["Hello", "Hola", "Bonjour",
                     "Ciao", "こんにちは", "안녕하세요",
                     "Cześć", "Olá", "Здравствуйте",
                     "Chào bạn", "您好", "Hallo",
                     "Hej"];

    for (num, greeting) in greetings.iter().enumerate() {
        print!("{} : ", greeting);
        match num {
            0 =>  println!("This code is editable and runnable!"),
            1 =>  println!("¡Este código es editable y ejecutable!"),
            2 =>  println!("Ce code est modifiable et exécutable !"),
            3 =>  println!("Questo codice è modificabile ed eseguibile!"),
            4 =>  println!("このコードは編集して実行出来ます!"),
            5 =>  println!("여기에서 코드를 수정하고 실행할 수 있습니다!"),
            6 =>  println!("Ten kod można edytować oraz uruchomić!"),
            7 =>  println!("Este código é editável e executável!"),
            8 =>  println!("Этот код можно отредактировать и запустить!"),
            9 =>  println!("Bạn có thể edit và run code trực tiếp!"),
            10 => println!("这段代码是可以编辑并且能够运行的!"),
            11 => println!("Dieser Code kann bearbeitet und ausgeführt werden!"),
            12 => println!("Den här koden kan redigeras och köras!"),
            _ =>  {},
        }
    }
}

Other code written in Rust (example of Array and Slices):

use std::mem;

// This function borrows a slice
fn analyze_slice(slice: &[i32]) {
    println!("first element of the slice: {}", slice[0]);
    println!("the slice has {} elements", slice.len());
}

fn main() {
    // Fixed-size array (type signature is superfluous)
    let xs: [i32; 5] = [1, 2, 3, 4, 5];

    // All elements can be initialized to the same value
    let ys: [i32; 500] = [0; 500];

    // Indexing starts at 0
    println!("first element of the array: {}", xs[0]);
    println!("second element of the array: {}", xs[1]);

    // `len` returns the size of the array
    println!("array size: {}", xs.len());

    // Arrays are stack allocated
    println!("array occupies {} bytes", mem::size_of_val(&xs));

    // Arrays can be automatically borrowed as slices
    println!("borrow the whole array as a slice");
    analyze_slice(&xs);

    // Slices can point to a section of an array
    println!("borrow a section of the array as a slice");
    analyze_slice(&ys[1 .. 4]);

    // Out of bound indexing yields a panic
    println!("{}", xs[5]);
}

If're not familiar with almost none of this code. I extremally recommend you to stop few minutes on Rust by Example.

Why it Right Now?

JavaScript was created in 1995. It wasn’t designed to be fast, and for the first decade, it wasn’t fast. Then the browsers started getting more competitive.

In 2008, a period that people call the performance wars began. Multiple browsers added just-in-time compilers, also called JITs. As JavaScript was running, the JIT could see patterns and make the code run faster based on those patterns.

The introduction of these JITs led to an inflection point in the performance of JavaScript. Execution of JS was 10x faster.

With this improved performance, JavaScript started being used for things no one ever expected it to be used for, like server-side programming with Node.js. The performance improvement made it feasible to use JavaScript on a whole new class of problems.

We may be at another one of those inflection points now, with WebAssembly.

Installing

  1. Setup rustup

Rustup is an official Rust project that allows us to install, manage, and update multiple Rust toolchains.

curl https://sh.rustup.rs -sSf | sh

After we’ll be prompted to run the following command to update the current shell with the changes:

source $HOME/.cargo/env

Add the wasm32-unknown-emscripten compile target via rustup as well:

rustup target add wasm32-unknown-emscripten

Set up Emscripten via emsdk. We’ll use the incoming version of Emscripten in order to get the best output.

# Make sure to have cmake installed before running this:
# - Ubuntu/Debian: apt install cmake
# - MacOS X : brew install cmake
curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | tar -zxv -C ~/
cd ~/emsdk-portable
./emsdk update
./emsdk install sdk-incoming-64bit
./emsdk activate sdk-incoming-64bit

Emscripten is installed.

The last command will instruct us how to add the binaries to our path for permanent usage, or we can just source ./emsdk_env.sh for temporary fun.

$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.37.22
clang version 4.0.0 (https://github.com/kripken/emscripten-fastcomp-clang.git 3659f873b523e5fc89ffa16baab8901fbd084251) (https://github.com/kripken/emscripten-fastcomp.git de9659961c692174fc4651a6ea0720236e4c4739) (emscripten 1.37.22 : 1.37.22)
Target: x86_64-apple-darwin17.2.0
Thread model: posix
InstalledDir: /Users/raphael.amorim/emsdk-portable/clang/fastcomp/build_incoming_64/bin
INFO:root:(Emscripten: Running sanity checks)

Let’s create the project.

cargo init wasm-demo --bin && rustup override set nightly

Put our first code sample into src/main.rs:

#[derive(Debug)]
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);
}

Run it to see what happens:

$ cargo run
   Compiling wasm-rust v0.1.0 (file:///Users/raphael.amorim/Documents/gcom/webassembly-and-rust/examples/wasm-rust)
   Finished dev [unoptimized + debuginfo] target(s) in 0.66 secs
   Running `target/debug/wasm-rust`
South
false

Let's build for browsers:

cargo build --target=wasm32-unknown-emscripten --release

Run tree on target folder:

$ tree target
target
├── debug
│   ├── build
│   ├── deps
│   │   ├── wasm_rust-34c6ef5f29bee9df
│   │   └── wasm_rust-34c6ef5f29bee9df.dSYM
│   │       └── Contents
│   │           ├── Info.plist
│   │           └── Resources
│   │               └── DWARF
│   │                   └── wasm_rust-34c6ef5f29bee9df
│   ├── examples
│   ├── incremental
│   ├── native
│   ├── wasm-rust
│   ├── wasm-rust.d
│   └── wasm-rust.dSYM -> /Users/raphael.amorim/Documents/gcom/webassembly-and-rust/examples/wasm-rust/target/debug/deps/wasm_rust-34c6ef5f29bee9df.dSYM
├── release
│   ├── build
│   ├── deps
│   ├── examples
│   ├── incremental
│   └── native
└── wasm32-unknown-emscripten
    └── release
        ├── build
        ├── deps
        │   ├── wasm-rust.js
        │   └── wasm_rust.wasm
        ├── examples
        ├── incremental
        ├── native
        ├── wasm-rust.d
        ├── wasm-rust.js
        ├── wasm_rust.d
        └── wasm_rust.wasm

cargo created several files in target/wasm32-unknown-emscripten/release/deps/ for us. Of primary interest are the .wasm and .js files.

Why do we get both a wasm and a js? Wasn’t the whole point of this to not use Javascript? Turns out we need some Javascript glue code to fetch, initialize, and configure it.

Create a site/index.html with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Wasm/Rust</title>
  <script>
    // This is read and used by `site.js`
    var Module = {
      wasmBinaryFile: "wasm_demo.wasm"
    }
  </script>
  <script src="site.js"></script>
</head>
<body></body>
</html>

Let's automatize it with Makefile, set up some way to get the generated files from the target/ folder into the site/ folder (* use tabs):

SHELL := /bin/bash

all:
  cargo build --target=wasm32-unknown-emscripten --release
  mkdir -p site
  find target/wasm32-unknown-emscripten/release/deps -type f -name "*.wasm" | xargs -I {} cp {} site/wasm_demo.wasm
  find target/wasm32-unknown-emscripten/release/deps -type f ! -name "*.asm.js" -name "*.js" | xargs -I {} cp {} site/site.js

Run make and see the tree:

$ tree site
site
├── index.html
├── site.js
└── wasm_demo.wasm

Let’s test our generated code by running python -m SimpleHTTPServer, browsing to http://localhost:8000/site/, and opening the browser console.

Example Wasm

Wasm and Rust Called from Javascript

Link to example

src/main.rs

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", "recieve");
    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.
}

In Client-side:

var Module = {
  wasmBinaryFile: "site.wasm",
  onRuntimeInitialized: main,
};
function main() {
  var getData = Module.cwrap('get_data', 'string', []);
  console.log(getData());
};

Example

Credits

Thanks to hoverbear by examples and Rust/Wasm setup guide.

References

More Repositories

1

react-tv

[ Unmaintained due to raphamorim/react-ape ] React Renderer for low memory applications
JavaScript
2,014
star
2

react-ape

🦍• React Renderer to build UI interfaces using canvas/WebGL (TV and Hardware-Accelerated GPU development based)
JavaScript
1,513
star
3

awesome-canvas

A curated list of awesome HTML5 Canvas with examples, related articles and posts.
Markdown
1,399
star
4

lucario

The best flat theme for Vim, Atom, Sublime Text, Jetbrains Editors, Terminal.app, iTerm, Xcode, Windows Terminal and XTerm
Vim Script
797
star
5

origami.js

Powerful and Lightweight Library to create using HTML5 Canvas
JavaScript
765
star
6

waterfall.js

Tired of use creepy hacks or heavy ways to get a Grid based on Pinterest?
JavaScript
540
star
7

native-css

Convert pure CSS to React Style or javascript literal objects.
JavaScript
340
star
8

write-code-every-day

[No longer maintained] :octocat: A project to honor those developers who believed in the challenge.
HTML
170
star
9

retro

[Work in Progress] Minimalist Vim Based Editor for the 30th Century
JavaScript
105
star
10

go-rainbow

Golang Helper for beautiful CLI Applications
Go
89
star
11

react-motions

Compose React Animations using High-Order Functions or Components
CSS
88
star
12

imgStatus

[855bytes] Detect when images have been loaded without jQuery
JavaScript
65
star
13

xwasm

[Work In Progress] WebAssembly Packager and WASM tooling for modern frontend
JavaScript
55
star
14

clapton

Yet Another Open Source Desktop Media Player
JavaScript
50
star
15

canvas-experiments

Some experiments using Canvas HTML5 technology.
JavaScript
46
star
16

inphinity

A infinity scroll without jQuery or other dependency.
JavaScript
45
star
17

calendario

📆 Check if a day is a workday or holiday
JavaScript
37
star
18

firefox-offline-game

Mozillian fork from Chromium T-Rex Game
JavaScript
35
star
19

ranza

The dependency checker
JavaScript
30
star
20

LR35902

Gameboy Emulator written in Rust and WebAssembly. 8-bit microprocessor: Sharp LR35902.
Rust
28
star
21

memory-inspector

Memory Inspector watches memory usage/behaviour of an Web Application
JavaScript
22
star
22

wat

[fsnotify] A cross-platform File Watcher that runs specific tasks when specific files are added, changed or deleted
Go
21
star
23

cargo-server

serve a static site, single page application or just a static file with Rust
Rust
21
star
24

elekid

Resolver for React's Server Side Render on Module, ReactElement or Electron
JavaScript
19
star
25

kyoto

Kyoto Lang - A programming language designed to build WebAssembly
Rust
19
star
26

nautilus.js

Async CSS/JavaScript loader & dependency manager in ~1kb (600B gziped)
JavaScript
18
star
27

react-song

React renderer to MIDI, Custom Notes, ArrayBuffers and Base64 based on Songs
JavaScript
18
star
28

off-the-hook

[WIP] React Hooks that I use in my personal projects or I've created just for fun.
JavaScript
16
star
29

webpack-2-vs-rollup

Comparison between Webpack 2 and Rollup
JavaScript
14
star
30

treeData.js

A JavaScript plugin to easy create an tree data structure.
CSS
14
star
31

js2c

[WIP] Transform JavaScript into ANSI C
JavaScript
14
star
32

angular-drag-n-drop

Angular Drag and Drop, with no dependency on Jquery or other library.
JavaScript
13
star
33

just-canvas

Dancing using JavaScript - Canvas HTML5 Feature
JavaScript
13
star
34

algorithms

Solutions to algorithmic problems
JavaScript
13
star
35

redux-ssr-shopping-cart

A complete sample of React + Redux + Server Side Render + GraphQL + Express + MongoDB
JavaScript
13
star
36

awesome-conduct

Be Truly Awesome
12
star
37

sound-hunter

Increase speed for search, finding songs in less than 5 minutes
CSS
12
star
38

astrofish

A intergalactic theme based on Spacemacs Color Scheme
Vim Script
11
star
39

reactsandbox

Create a React Component Sandboxes based on compositions
JavaScript
11
star
40

mugiwara

fast minimal CSS-in-JS created to reduce size of CSS injected
JavaScript
11
star
41

tzu

The belt of number conversion for nodejs
JavaScript
10
star
42

500-dias-de-open-source

Meu livro que retrata a experiencia de ter mergulhado de cabeça no mundo open source e escrever código útil diariamente por 500 dias seguidos.
Shell
10
star
43

raphamorim-keynote-theme

My own keynote theme :))
9
star
44

how-to-write-your-react-renderer

Slides: http://raphamorim.io/how-to-write-your-react-renderer
JavaScript
8
star
45

webassembly-image-editor

Image Editor powered by WebAssembly and Rust
JavaScript
8
star
46

kenobi

Render objects for view engines or static html
JavaScript
7
star
47

nbfs

NonBlocking ~Nodejs~ File System
JavaScript
6
star
48

aQuery

jQuery chunk [<=1kb]
JavaScript
6
star
49

rust-dockerclient

Rust client for the Docker remote API
Rust
6
star
50

blonde

Paintfull setup no more
JavaScript
5
star
51

origamijs

Origami.js Site
CSS
5
star
52

capivara

[no longer maintained] Generates & Obtain DOM (Document Object Model)
Python
5
star
53

500-days

http://raphamorim.io/500-days/
JavaScript
4
star
54

shell-script-frontend

[WIP] Replace grunt / gulp tasks using Shell Script
Shell
4
star
55

react-ape-movie-list-demo

Demo with React Ape
JavaScript
4
star
56

axum-service-checklist

Template for Rust API with Axum and Tokio
Rust
3
star
57

react-blessed-task-list

JavaScript
3
star
58

retroeditor.io

[Deprecated] Move to raphamorim/retro
HTML
3
star
59

raphamorim.github.com

A open blog plataform
JavaScript
2
star
60

Bring-Game-Boy-Alive-in-the-Web-with-Rust-and-WebAssembly-RustLab-2023

Rustlab 2023 talk
HTML
2
star
61

shells

My collection of shell scripts
Shell
2
star
62

skyrim-vr

Skyrim scenarios to Panoramic View using MozVR, thanks Skyrim360.
JavaScript
2
star
63

MapJs

The geolocation API and google maps working based only on your HTML.
JavaScript
2
star
64

500-days-of-open-source

My book about the write code every single day experience
2
star
65

tv-react-renderer-benchmark

Benchmark between renderers focused on memory
JavaScript
2
star
66

virtual.js

Use markup to create VR slide presentations that work across desktop, iOS, Android, and the Oculus Rift.
JavaScript
1
star
67

wa

Nothing to see here yet
Rust
1
star
68

arjs

Augmented Reality [拡張現実] JavaScript Library
JavaScript
1
star
69

suikoden-stars

A json data about all stars of destiny and how recruit in each suikoden game.
1
star
70

awesome-webgl

A curated list of awesome HTML5 Canvas with examples, related articles and posts.
1
star
71

chlog

[WIP] Changelog for Humans
JavaScript
1
star
72

js2c-set

Transform JS to C
JavaScript
1
star
73

rust-is-awesome

Personal list to check some resources which I've <3
1
star
74

The-good-developer

My book talks about how to become a better developer
HTML
1
star
75

react-conf-brasil

HTML
1
star
76

sayok

[EXPERIMENT] Terminal Notification for MacOS to notify Succeed Task
JavaScript
1
star
77

react-ape-preview

Service to run previews of React Ape render. Created specifically to react-ape docs
JavaScript
1
star
78

origami.svg

A Origami Plugin to deliver SVG instead Canvas (canvas to SVG)
JavaScript
1
star
79

canvas-icons

in development (Move Along, Nothing to See Here)
JavaScript
1
star
80

weird

Elixir
1
star
81

react-ape-photo-gallery

JavaScript
1
star
82

canvas-filter-tools

filter tools powered by wasm and canvas
JavaScript
1
star
83

offline-reader

Work in progress
JavaScript
1
star
84

rio

Rio is an opinionated package manager built with Rust for NodeJS ecosystem.
Rust
1
star
85

hackathon-1746

Projeto desenvolvido para solucionar o problema com a poda de árvores para a HackAthon 1746 realizado pela prefeitura do Rio de Janeiro
PHP
1
star