I’ve been using webassembly and rust for a couple months now, I’ll explain my usecase and some annoyances.
Currently, the plan of what I am doing is to run web asssembly inside a worker, which handles encryption to idb, indexing of data and basically most of the logic of the web app.
The way I do this is strange, I essentially have a web assembly module with a global singleton upon which functions can be called. The javascript calls the functions on the singleton, returns commands (io or other) the javascript should execute and then the javascript can call the web assembly after executing the commands.
The reasoning behind this approach, is because handling indexeddb, fetch, websockets and worker messages with webassembly seems implausible at the time. Also, a huge benefit is testability because you can mock anything. This also keeps web assembly as small as possible.
The way I communicate is via a JsBytes
struct, and serializing with a custom binary type to rust and from rust.
So far, this has worked well and the dom can actually treat the worker like a server, which is fantastic, and since the worker is implemented in web assembly, any computation heavy operations, like compression, decompression, encryption (which I do all except encryption and decryption so far) are fast.
The annoyances and pet peeves have been so far:
- Actually sending data between webassembly and js (or
ReasonMl
for me). After figuring out and getting the pattern down it is nice, however initially figuring it out was a pain.
- Startup time of web assembly, takes several hundred miliseconds.
- Needing the file system when using just the snappy compression lib (idk why)
- Compile times on the first compile (70 seconds), rest of the time it is 7ish seconds.
- Using multiple node versions (see: this), because I use a node dev server and emscripten
- Maybe more.
Overall however, after figuring out how to transfer data between the two, it isn’t too bad and I get many benefits with the web assembly and running it in the worker.
One nice thing is that I created a custom binary serialization format, for ReasonMl
and Rust
, it takes some rust definitions of structs and enums and creates a reason and rust file that will serialize to and from those structs. Reason/Ocaml and Rust both have nominal typings and similar enums, so they are a great fit.
For example defining this in rust:
enum Pet {
Cat(String),
Dog(String)
}
struct Person {
name: String,
age: i32
}
Will generate a module in reason:
module Pet = {
type t =
| Cat string
| Dog string;
let write v w => ...
let toBytes v => ...
let read r => ...
let fromBytes arr => ...
};
module Person = {
type t = {
name: string,
age: int,
}
let write v w => ...
let toBytes v => ...
let read r => ...
let fromBytes arr => ...
}
This will also generate rust types which have similar methods.
For transferring the bytes that get generated, I used JsBytes
which is here.
That makes it pretty simple to transfer data, without the context switch of a completely different type system.
Thats all.