Awesome
<!-- README.md is generated from README.Rmd. Please edit that file -->WebAssembly in R using wasmer
<!-- badges: start --> <!-- badges: end -->The goal of wasmr
is to run
WebAssembly
code from R using the wasmer runtime.
This is a early version with probably bugs, missing features and not the best code quality. But it already works and I am happy to hear feedback. The goal is that this package evolves into something stable.
The package is mainly written in C++ using the C API of the wasmer
runtime which is written in rust
. You therefore need a rust compiler
to install the package.
Installation
remotes::install_github("dirkschumacher/wasmr")
Also make sure to have a very recent rust compiler. The best way to install the rust toolchain is to use rustup.
Example
library(wasmr)
f <- system.file("examples/sum.wasm", package = "wasmr")
instance <- instantiate(f)
instance$exports$sum(10, 20)
#> [1] 30
f <- system.file("examples/hello.wasm", package = "wasmr")
instance <- instantiate(f)
memory_pointer <- instance$exports$hello()
hi <- instance$memory$get_memory_view(memory_pointer)
rawToChar(hi$get(1:11))
#> [1] "Hello world"
f <- system.file("examples/fib.wasm", package = "wasmr")
instance <- instantiate(f)
instance$exports$fib(20)
#> [1] 6765
fib <- function(n) {
if (n < 2) return(n)
fib(n - 1) + fib(n - 2)
}
microbenchmark::microbenchmark(
instance$exports$fib(20),
fib(20)
)
#> Unit: microseconds
#> expr min lq mean median
#> instance$exports$fib(20) 71.143 88.4745 158.3407 139.814
#> fib(20) 8037.195 9556.2085 13024.0362 10415.965
#> uq max neval
#> 150.472 1019.363 100
#> 14568.746 48506.287 100
Memory
f <- system.file("examples/fib.wasm", package = "wasmr")
instance <- instantiate(f)
instance$memory$get_memory_length()
#> [1] 2
# grow the number of pages
instance$memory$grow(1)
instance$memory$get_memory_length()
#> [1] 3
f <- system.file("examples/hello.wasm", package = "wasmr")
instance <- instantiate(f)
memory_pointer <- instance$exports$hello()
memory <- instance$memory$get_memory_view(memory_pointer)
memory$get(1:11)
#> [1] 48 65 6c 6c 6f 20 77 6f 72 6c 64
rawToChar(memory$get(1:11))
#> [1] "Hello world"
# you can also write to the internal memory
memory$set(5:6, charToRaw("o_"))
rawToChar(memory$get(1:11))
#> [1] "Hello_world"
Imports
set.seed(42)
imports <- list(
env = list(
add = typed_function(
function(a, b) {
# use R's RNG to add a random number to the result
a + b * as.integer(runif(1) * 100)
},
param_types = c("I32", "I32"),
return_type = "I32"
)
)
)
f <- system.file("examples/sum_import.wasm", package = "wasmr")
instance <- instantiate(f, imports)
# sum: add(a, b) + 42
instance$exports$sum(1, 5)
#> [1] 498
Caveats and limitations
- It is not feature complete and does not support everything that
wasm
supports - Imported functions can only have integer parameters
- No globals
- There is hardly any documentation except for the examples
I32/I64
are mapped toIntegerVector
andF32/F64
toNumericVector
. Currently no way to differentiate.- WIP
Inspiration and References
- wasmer Python - haven’t tried it but looked at the API/examples
- wasmer - especially the C api and the tests give some good examples.
- @jeroen ’s rust template
Contribute
While this is work in progress, the best way to contribute is to test the package and write/comment on issues. Before sending a PR it would great to post an issue first to discuss.
License
MIT just like wasmer.