# 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
