Orb logo

Orb: Write Composable WebAssembly using Elixir

Docs | Examples

Livebook: Temperature Converter

Features

Write WebAssembly using Elixir as your compiler:

I think of it as like how React’s JSX lets you write dynamic HTML in JavaScript, Orb lets you write dynamic WebAssembly in Elixir.

Status

Orb is alpha in active development. My aim is to refine the current feature set and complete a .wasm compiler (current it compiles to WebAssembly’s .wat text format) in order to get to beta.

Anti-Features

The following are a list of things that Orb has chosen not to support:

Libraries

Installation

Add orb to your list of dependencies in mix.exs:

def deps do
  [
    {:orb, "~> 0.2.2"}
  ]
end

Example

defmodule CalculateMean do
  use Orb

  global do
    @tally 0
    @count 0
  end

  defw insert(n: I32) do
    @tally = @tally + n
    @count = @count + 1
  end

  defw calculate_mean(), I32 do
    @tally / @count
  end
end

This can be converted to WebAssembly text format (wat):

wat = Orb.to_wat(CalculateMean)
# """
# (module $CalculateMean
#   (global $count (mut i32) (i32.const 0))
#   (global $tally (mut i32) (i32.const 0))
#   (func $insert (export "insert") (param $element i32)
#     (i32.add (global.get $count) (i32.const 1))
#     (global.set $count)
#     (i32.add (global.get $tally) (local.get $element))
#     (global.set $tally)
#   )
#   (func $calculate_mean (export "calculate_mean") (result i32)
#     (i32.div_s (global.get $tally) (global.get $count))
#   )
# )
# """

Write this out as a .wat WebAssembly text file:

File.write!("example.wat", wat)

You can then compile this to a .wasm WebAssembly file using wat2wasm from the WebAssembly Binary Toolkit:

wat2wasm example.wat

Or you can execute it directly in Elixir with OrbWasmtime:

alias OrbWasmtime.Instance

# Run above example
inst = Instance.run(CalculateMean)
Instance.call(inst, :insert, 4)
Instance.call(inst, :insert, 5)
Instance.call(inst, :insert, 6)
assert Instance.call(inst, :calculate_mean) == 5

Note there is another excellent Elixir Wasmtime wrapper out there called Wasmex, you may want to check that out too.

Composing modules

You can compose modules together using Orb.include/1:

defmodule Math do
  use Orb

  defw square(n: I32), I32 do
    n * n
  end
end

defmodule SomeOtherModule do
  use Orb

  Orb.include(Math)

  defw magic(), I32 do
    Math.square(3)
  end
end

Use cases

Why WebAssembly?

Why develop Orb in Elixir?

Here are the reasons I chose to write Orb in Elixir.