Current section
Files
Jump to
Current section
Files
CHEATSHEET.md
# Firebird Cheatsheet 🔥
## Install
```elixir
# mix.exs
{:firebird, "~> 1.0"}
```
Then: `mix deps.get`
## Verify Setup
```elixir
Firebird.check!() # Returns :ok if everything works
Firebird.demo() # Run interactive demo
wasm = Firebird.sample() # Pre-loaded instance for exploring
```
## Quick (Absolute Minimum)
```elixir
# Shortest possible way to run WASM:
8 = Firebird.quick(:sample, :add, [5, 3]) # bundled sample
8 = Firebird.quick("math.wasm", :add, [5, 3]) # auto-resolves path
42 = Firebird.quick("(module ...WAT...)", :fn, []) # inline WAT
```
## One-Liners
```elixir
# Load, call, stop — one step (single-value unwrapped)
{:ok, 8} = Firebird.run_one("math.wasm", :add, [5, 3])
8 = Firebird.run_one!("math.wasm", :add, [5, 3])
# List-wrapped (original API)
{:ok, [8]} = Firebird.run("math.wasm", :add, [5, 3])
[8] = Firebird.run!("math.wasm", :add, [5, 3])
```
## Load & Call
```elixir
{:ok, wasm} = Firebird.load("math.wasm") # from file
wasm = Firebird.load!("math.wasm") # bang version
{:ok, wasm} = Firebird.load(bytes) # from binary
{:ok, wasm} = Firebird.load("app.wasm", wasi: true) # Go/WASI modules
# Single-value return (recommended for most functions)
{:ok, 8} = Firebird.call_one(wasm, :add, [5, 3]) # unwrapped single value
8 = Firebird.call_one!(wasm, :add, [5, 3]) # raises on error
# List return (for multi-value or explicit matching)
{:ok, [8]} = Firebird.call(wasm, :add, [5, 3]) # ok/error tuple
[8] = Firebird.call!(wasm, :add, [5, 3]) # raises on error
Firebird.stop(wasm) # clean up
```
## Pipe-Friendly API
```elixir
wasm = Firebird.load!("math.wasm")
{[sum], wasm} = Firebird.pipe!(wasm, :add, [5, 3])
{[product], wasm} = Firebird.pipe!(wasm, :multiply, [sum, 2])
Firebird.stop(wasm)
```
## Block API (auto-cleanup)
```elixir
{:ok, result} = Firebird.with_instance("math.wasm", fn wasm ->
{:ok, [a]} = Firebird.call(wasm, :add, [5, 3])
{:ok, [b]} = Firebird.call(wasm, :multiply, [a, 2])
b
end)
# => {:ok, 16}
```
## Declarative Module
```elixir
defmodule MyApp.Math do
use Firebird, wasm: "priv/wasm/math.wasm" # shortcut!
wasm_fn :add, args: 2
wasm_fn :multiply, args: 2
wasm_fn :fibonacci, args: 1
end
# Auto-discover all exports:
defmodule MyApp.Math do
use Firebird, wasm: "priv/wasm/math.wasm", auto: true
end
# In supervision tree:
children = [MyApp.Math]
# Then call anywhere:
{:ok, [8]} = MyApp.Math.add(5, 3)
[8] = MyApp.Math.add!(5, 3)
```
## Pool (Concurrent)
```elixir
# In supervision tree:
children = [
{Firebird.Pool, wasm: "math.wasm", size: 4, name: :math}
]
# Call (auto-distributed across instances):
{:ok, [8]} = Firebird.Pool.call(:math, :add, [5, 3])
[8] = Firebird.Pool.call!(:math, :add, [5, 3])
```
## Inline WAT (Prototyping)
```elixir
import Firebird.Sigils
# Compile-time (zero runtime overhead)
bytes = wat!("""
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0 local.get 1 i32.add))
""")
{:ok, wasm} = Firebird.load(bytes)
# Runtime
{:ok, bytes} = wat("(module)")
# Quick eval
{:ok, [42]} = Firebird.Quick.eval_wat("(module (func (export \"f\") (result i32) i32.const 42))", "f")
# Load as function map
fns = Firebird.Quick.load_as_functions("math.wasm")
{:ok, [8]} = fns.add.([5, 3])
fns.__stop__.()
```
## Lazy Loading (Load on First Use)
```elixir
# In supervision tree:
children = [
{Firebird.Lazy, wasm: "priv/wasm/math.wasm", name: :lazy_math}
]
# WASM loads on first call (not at startup)
{:ok, [8]} = Firebird.Lazy.call(:lazy_math, :add, [5, 3])
```
## Stream Integration
```elixir
{:ok, wasm} = Firebird.load("math.wasm")
# Map WASM function over data
1..10 |> Firebird.Stream.map(wasm, :fibonacci) |> Enum.to_list()
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# Filter with WASM predicate
1..20 |> Firebird.Stream.filter(wasm, :is_prime) |> Enum.to_list()
# Reduce with WASM function
1..10 |> Firebird.Stream.reduce(wasm, :add, 0) # => 55
# Compose!
1..100
|> Firebird.Stream.filter(wasm, :is_prime)
|> Firebird.Stream.map(wasm, :fibonacci)
|> Enum.take(5)
```
## Unwrap Results
```elixir
# Preferred: use call_one / run_one
{:ok, 8} = Firebird.call_one(wasm, :add, [5, 3])
8 = Firebird.run_one!("math.wasm", :add, [5, 3])
# Alternative: pipe through unwrap
import Firebird.Unwrap
{:ok, 8} = Firebird.run("math.wasm", :add, [5, 3]) |> unwrap()
8 = Firebird.run!("math.wasm", :add, [5, 3]) |> unwrap!()
```
## Introspection
```elixir
Firebird.exports(wasm) # => [:add, :multiply, ...]
Firebird.functions(wasm) # => [%{name: :add, params: [:i32, :i32], results: [:i32], arity: 2}, ...]
Firebird.all_exports(wasm) # => [{"add", :function}, ...]
Firebird.function_exists?(wasm, :add) # => true
Firebird.function_type(wasm, :add) # => {:ok, {[:i32, :i32], [:i32]}}
Firebird.alive?(wasm) # => true
Firebird.info(wasm) # => %{alive: true, exports: [...], memory_bytes: 65536}
Firebird.describe(wasm) # Print human-readable summary
Firebird.describe("file.wasm") # Print file info
```
## Memory
```elixir
Firebird.write_memory(wasm, 0, <<1, 2, 3>>)
{:ok, bytes} = Firebird.read_memory(wasm, 0, 3)
{:ok, size} = Firebird.memory_size(wasm)
{:ok, _old} = Firebird.grow_memory(wasm, 1) # +64KB
```
## Batch
```elixir
{:ok, [[3], [12]]} = Firebird.call_many(wasm, [
{:add, [1, 2]},
{:multiply, [3, 4]}
])
```
## Testing
```elixir
# Recommended: use Firebird.TestCase (handles setup + cleanup automatically)
defmodule MyTest do
use Firebird.TestCase, wasm: "path/to/module.wasm"
# or: use Firebird.TestCase # Bundled sample (no path needed!)
# or: use Firebird.TestCase, wasm: false # Just helpers, no auto-loading
test "it works", %{wasm: wasm} do
assert_wasm_result wasm, :add, [5, 3], 8 # unwrapped single value
assert_wasm_call wasm, :add, [5, 3], [8] # list-wrapped
assert_wasm_exports wasm, [:add, :multiply]
refute_wasm_exports wasm, [:nonexistent] # assert NOT exported
assert_wasm_type wasm, :add, {[:i32, :i32], [:i32]}
assert_wasm_function wasm, :add, 2
assert_wasm_error wasm, :nonexistent, [1]
assert_wasm_fast wasm, :add, [5, 3], 100 # < 100ms
# Table-driven: verify many input/output pairs at once
assert_wasm_table wasm, :add, [
{[0, 0], 0},
{[1, 2], 3},
{[5, 3], 8},
{[100, 200], 300}
]
# Pipeline: test chained WASM calls
assert_wasm_pipeline wasm, [
{:add, [5, 3]},
{:multiply, [:_, 2]}
], [16]
# Range: verify result is within bounds
assert_wasm_between wasm, :fibonacci, [10], 50, 60
end
end
```
### Pool Testing
```elixir
defmodule MyApp.PoolTest do
use ExUnit.Case, async: false
import Firebird.TestHelpers
setup_pool "priv/wasm/math.wasm", size: 4
test "pool call", %{pool: pool} do
{:ok, [8]} = Firebird.Pool.call(pool, :add, [5, 3])
end
end
```
## Validation
```elixir
:ok = Firebird.validate("math.wasm") # Check file is loadable
{:error, _} = Firebird.validate("bad.txt") # Returns error details
```
## Mix Tasks
```bash
# Setup & Diagnostics
mix firebird # List all available tasks
mix firebird.doctor # Diagnose setup issues
mix firebird.new my_app # New project from scratch
mix firebird.init # Setup in existing project
mix firebird.init --rust # + Rust scaffold
mix firebird.init --phoenix # + Phoenix helpers
# Code Generation & Inspection
mix firebird.gen module.wasm # Generate wrapper from WASM
mix firebird.gen module.wasm --style pool # Pool-backed wrapper
mix firebird.inspect module.wasm # Inspect WASM exports
# Building & Testing
mix firebird.build # Build WASM fixtures from source
mix firebird.test # Run WASM-related tests
mix firebird.bench # Run benchmarks
# Elixir → WASM Compilation
mix firebird.compile # Compile Elixir → WASM
mix firebird.analyze lib/ # Analyze source files
mix firebird.target # Build Elixir → WASM target
mix firebird.target.new MyModule # Generate WASM-ready module
mix firebird.target.watch # Watch and recompile on changes
mix firebird.target.check # Check WASM compilability
mix firebird.target.bench # Benchmark WASM vs BEAM
mix firebird.target.verify # Verify compiled WASM modules
mix firebird.target.inspect # Inspect compilation pipeline
mix firebird.target.profile # Profile compilation pipeline
mix firebird.target.report # Generate compilation report
mix firebird.target.status # Show compilation status
mix firebird.target.link # Link modules into single WASM
mix firebird.target.clean # Clean compilation artifacts
# Phoenix Integration
mix firebird.phoenix # Phoenix WASM tools
mix firebird.phoenix.gen my_app # Generate Phoenix WASM project
```
## Create WASM (Rust)
```rust
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b }
```
```bash
cargo build --target wasm32-unknown-unknown --release
```
## Create WASM (Go)
```go
//export add
func add(a, b int32) int32 { return a + b }
func main() {}
```
```bash
GOOS=wasip1 GOARCH=wasm go build -o module.wasm
```
## See Also
- [Decision Guide](docs/DECISION_GUIDE.md) — Which API? WASM vs BEAM? Pool vs Module?
- [Getting Started](docs/GETTING_STARTED.md) — Step-by-step setup
- [FAQ](docs/FAQ.md) — Common questions (`call` vs `call_one`, strings, pools, performance)
- [API Reference](docs/API.md) — Complete function reference
- [Cookbook](docs/COOKBOOK.md) — Real-world recipes
- [Testing Guide](docs/TESTING_GUIDE.md) — Testing patterns and assertions
- [Troubleshooting](docs/TROUBLESHOOTING.md) — Error solutions