Rust and WebAssembly for masses - Introduction
Tags: rust, webassembly, webdev, beginners
Published: 2020-01-01 16:36:07


# Rust 

> The [Rust language](https://www.rust-lang.org) is designed to guide you naturally towards reliable goal that is efficient in terms of speed and memory usage  - _Nicholas Matsakis and Aaron Turon_

Rust is a [systems-level programming language](https://en.wikipedia.org/wiki/System_programming_language). Rust provides _low-level memory management_ to represent data efficiently. 

Rust ensures **safety**. This makes it easy to write applications and not to worry about [dangling pointers](https://en.wikipedia.org/wiki/Dangling_pointer).

Rust makes [concurrency](https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html) painless.

Being a modern language, Rust provides well defined (designed) APIs. This makes Rust a desirable language while _designing high performant applications_, _Command Line Interface applications_ (CLI apps) and others.

---

Check out my book on Rust and WebAssembly [here](https://sendilkumarn.com/wasm-book)

---

One of Rust's standout features is its `compiler`. The compiler guides you when making mistakes and empowers you to write `better code`.

The _ownership model_ in Rust guarantees thread and memory safety. 

> Overall Rust ensures safety, concurrency, and makes you stay away from risks, crashes, and vulnerabilities.

## World of Rust Web

Rust slowly but steadily progressing into the [world of web development](https://www.arewewebyet.org). 

Rust is easy to get started (if you wrap your head around the [ownership model](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)) and backed by an [awesome community](https://www.rust-lang.org/governance/teams/core) that is ready to help.


Rust provides the `first class` support for the WebAssembly. Rust and WebAssembly toolchain makes it easier and faster to get started with WebAssembly.

JavaScript is `easy`. They enabled millions (even billions) of developers to start writing applications. The fast feedback loop while development and simple API. JavaScript provides a good performance. When optimised correctly, JavaScript may yield a `better performance`.

The performance that JavaScript provides is not reliable and consistent. Any optimisations to increase performance is not consistent across various JavaScript engines. This makes it difficult for developers to give a better optimised and consistent performance with JavaScript.

## WebAssembly 

[WebAssembly](https://webassembly.org) promises better performance because it is _statically typed, compiled, optimised for production, uses linear memory layout_, and others.

WebAssembly makes it easy to run native code in the browser. Rust makes it easy to convert Rust to WebAssembly binary code. 
 
Rust has the _best tooling support_ that integrates well with tools that are familiar to JavaScript developers.

---

## Setting up Rust toolchain for WebAssembly

[Emscripten](https://emscripten.org) simplifies setting up the environment for compiling the C or C++ into the WebAssembly modules.

Rust considers WebAssembly as the first-class citizen. It provides a much better toolchain and support for WebAssembly. 

Rust built its own WebAssembly toolchain inside the standard rust compiler (`rustc`). This enabled Rust developers to compile the Rust code into WebAssembly Modules.

[Rustup](https://rustup.rs) is the _Rust installer and version management tool_. The Rustup tool is similar to [nvm](https://github.com/nvm-sh/nvm) for Node.js.  Rustup helps to install, update, and remove the `rustc`, `cargo`, and `rustup` itself.

[Rustc](https://doc.rust-lang.org/rustc/what-is-rustc.html) is the Rust Compiler. It converts your source code into the library or executable.

[Cargo](https://doc.rust-lang.org/cargo/) is the package manager for Rust. Cargo is similar to Node's NPM. Cargo downloads the package dependencies, compiles, packs, and uploads them to the Rust crates library (crates.io).

> Cargo downloads your Rust project's dependencies and compiles your project. - Cargo team

Cargo makes it easier to create, run, download, compile, test, and run your project. The cargo command internally calls the rustc compiler to execute the compilation.

### Install Rust 

So let's begin:

To install Rust with the `rustup` command.

In Linux or MacOs

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

The script will download the script file and runs it. The script will install the Rust language.  Both `rustc` and `cargo` are installed in the `~/.cargo/bin` and delegates any access to the underlying toolchain.

Once the installation is completed successfully, you can check the installation by running.

```
$ rustc --version
rustc 1.40.0 (73528e339 2019-12-16)
```

For Windows:

To install the Rustup, Download the Rustup from the binaries available [here](https://forge.rust-lang.org/other-installation-methods.html). Both rustc and cargo are installed in the users folder.

> Note that you will require C++ build tools for Visual Studio 2013 or later. You can install them from [here](https://visualstudio.microsoft.com/downloads/)

Check the installation by running `rustc --version`


### Rustup

The `Rustup` is a toolchain multiplexer. It installs and manages many Rust toolchains and proxies them through the single set of tools installed at `.cargo/bin` in the home directory. 

Once the rustup command is installed, we can easily manage the `rustc` and `cargo` compilers. The rustup also makes it easy to switch between nightly, stable, and beta versions of Rust.

The Rust and WebAssembly is available in the Stable version of the Rust (version 1.30 and above). We will switch to the `nightly` build to make sure we get all the latest benefits.

To switch to the nightly version, we have to run

```
$ rustup default nightly
```

The above command will switch the default Rust compiler to the `nightly` version. The rustc proxy in the `~/.cargo/bin` will run the nightly compiler instead of the stable compiler.

To update to the latest version of nightly we can run

```
$ rustup update
```

Once successfully updated, we can check the current version installed by running

```
$ rustc --version
rustc 1.42.0-nightly (da3629b05 2019-12-29)
```

Rust to WebAssembly compiler is built in with the default rustc compiler.  This means the above toolchain setup is now capable of compiling your Rust code into WebAssembly modules. Let us see that in action.

---

## Rust to WebAssembly 

If you are thinking that the WebAssembly is best suited for the gaming applications, Online IDE, and other resource-intensive and memory hungry applications then you are technically correct. But we can reap the benefits of WebAssembly benefits in a simple application too.

For a normal application (i.e., applications that do not need ultra fast responses always) that we develop will have some parts that need performance tuning. Sometimes we have to remove that ugly spaghetti code that runs only on certain browsers and not on the others. WebAssembly provides an option here.

With Rust and WebAssembly, it is easy to patch those areas with faster, consistent WebAssembly code and use the application as such.

The tooling in the Rust for WebAssembly is the best at the moment. With Rust, you can either create an entire application with Rust (i.e., both the front and back end) or use Rust for a part of the application.

The Rust compiler uses [LLVM](https://llvm.org) underneath for converting the Rust source code into WebAssembly modules.

Read more about targets [here](https://doc.rust-lang.org/rustc/targets/index.html)

## target wasm32-unknown-unknown

In order to create WebAssembly modules using Rust's toolchain we will be using the target `wasm32-unknown-unknown`.

Here the `unknown-unknown` instructs the compiler that the code can compile on any machine and run on any machine. This will create WebAssembly modules that will run on any machine.

We can install `wasm32-unknown-unknown` using 

```
$ rustup target add wasm32-unknown-unknown
```

The `wasm32-unknown-unknown` target adds zero runtime and toolchain footprint. The former is because the target assumes only `wasm32` instruction set is present. The latter is because you do not need a special compiler or toolchain or custom linker to compile.

### Write some code ✍️

Create a new project with cargo.

```
$ cargo new --lib car_fib
Created library `car_fib` package
```

A new project called car_fib is created. The `--lib` flag to inform the cargo to create a new library project rather than the default binary project.

> The binary project will produce the executable or the actual binaries that will run. In our case, we are just building a library and then create WebAssembly modules out of it.

Spin up our favourite text editor and replace the contents of the `src/lib.rs` with the following.

```
#[no_mangle]
fn add(x: i32, y:i32) -> i32 {
    x + y
}
```

The `#[no_mangle]` annotation informs the compiler to not to mangle the names when generating the library.

We have to specify the compiler what type of crate we are compiling. We can specify the `crate-type` in the `Cargo.toml` file that is generated. 
 
Open the `Cargo.toml` and add the crate-type information inside.

```
[package]
name = "car_fib"
version = "0.1.0"
authors = ["Sendil Kumar"]

[lib]
crate-type = ["cdylib"]
```

The `cdylib` crate-type generates a `dynamic system library`. This dynamic system library is used when the library has to be loaded from another language.

Let us compile the Rust to WebAssembly module.

```
$ cargo build --target wasm32-unknown-unknown
```

The `cargo build` calls the rust compiler. The Rust compiler use the specified target `wasm32-unknown-unknown`. It generates the WebAssembly module inside `/target/wasm32-unknown-unknown/`.

Create an HTML file

```
$ touch index.html
```

Add the following contents in `index.html`:

```
<script>
 (async () => {
     const bytes = await fetch("target/wasm32-unknown-unknown/debug/car_fib.wasm");
     const response = await bytes.arrayBuffer();
     const result = await WebAssembly.instantiate(response, {});
     console.log(result.instance.exports.add(10,3));
 })();
</script>
```

We have used [async-await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) here to make the syntax more elegant and contextually easier to understand. 

First we fetch the WebAssembly module using the `fetch`. The `bytes.arrayBuffer()` returns the promise that resolves with an `ArrayBuffer`. 

The `WebAssembly.instantiate` function allows you to compile and instantiate WebAssembly code. The resulting object have the exported methods. 

As expected, this will print the output `13`.

### What has happened?

Here the cargo build command invokes rust compiler and compiles the Rust code to MIR (Middle Intermediate Representation) then into LLVM IR. The generated LLVM IR is then converted into WebAssembly module.


![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/3p93jecfi2t7p26tvboh.png)


It is important to note that we did not use [emscripten compiler](https://emscripten.org) here, everything is handled by the rust compiler itself.

Let us add another function. We can create a Fibonacci number generator with Rust and run them on the browser.

Open the `car_fib.rs`, replace everything with the following contents

```
#[no_mangle]
fn fibonacci(num: i32) -> i32 {
    match num {
        0 => 0,
        1 => 1,
        _ => fibonacci(num-1) + fibonacci(num-2),
    }
}
```

Build it using the `cargo build --target wasm32-unknown-unknown`.

Finally, replace the `index.html` such that we call the Fibonacci instead of the add.

```
<script>
 (async () => {
     const bytes = await fetch("target/wasm32-unknown-unknown/debug/car_fib.wasm");
     const response = await bytes.arrayBuffer();
     const result = await WebAssembly.instantiate(response, {});
     console.log(result.instance.exports.fibonacci(20));

 })();
</script>
```

Now spin up the HTML server and check the browser's console for the fibonacci value.

In the next blog let us see how to pass various values between JavaScript and WebAssembly module.

---

If you have enjoyed the post, then you might like my book on Rust and WebAssembly. Check them out [here](https://sendilkumarn.com/wasm-book)

---

---

👇 Repo 👇

{% github sendilkumarn/rustwasm-introduction no-readme %}

---

### Interested to explore more...

More information about the linking [here](https://doc.rust-lang.org/reference/linkage.html)

You can check more about async-await [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction)

---

Discussions [🐦 Twitter](https://twitter.com/sendilkumarn) // [💻 GitHub](https://github.com/sendilkumarn) // [✍️ Blog](https://sendilkumarn.com/blog) // [🔸 HackerNews](https://news.ycombinator.com/item?id=22048003)

If you like this article, please leave a like or a comment. ❤️

---