wit.mbt

moon add mizchi/wit.mbt@0.1.0
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
6 months ago
Downloads
20

Dependencies

README

#mizchi/moon_component

WebAssembly Component Model tooling for MoonBit.

#Installation

# Build the CLI cargo build --release --manifest-path tools/moon-component/Cargo.toml # Add to PATH (optional) export PATH="$PWD/tools/moon-component/target/release:$PATH"

#Quick Start

# Create a new component project moon-component new my-component # Or initialize in existing MoonBit project moon-component init # Build component (generate + build + componentize) moon-component component wit/world.wit -o my-component.wasm --release

#Commands

#moon-component new <name>

Create a new MoonBit component project with example WIT file.

moon-component new hello-world cd hello-world moon-component component wit/world.wit -o hello.wasm --release

#moon-component generate <wit-path>

Generate MoonBit bindings from WIT files.

moon-component generate wit/world.wit -o ./component -p my/project

Options:
  • -o, --out-dir <dir> - Output directory (default: .)
  • -p, --project-name <name> - Project name for imports
  • --gen-dir <dir> - Generated code directory (default: gen)
  • --impl-dir <dir> - Implementation directory (default: impl)
  • --no-impl - Don't generate impl files
  • --wkg - Generate wkg.toml for wa.dev deployment
  • -w, --world <world> - World to generate bindings for

#moon-component component <wit-path>

Full workflow: generate + build + componentize.

moon-component component wit/world.wit -o output.wasm --release

#moon-component componentize <wasm-path>

Create a WebAssembly component from a built wasm module.

moon build --target wasm --release moon-component componentize target/wasm/release/build/main/main.wasm \ --wit-dir wit -o component.wasm

#moon-component plug <socket> <plugs>...

Plug component exports into another component's imports (using wac plug).

# Plug library.wasm exports into app.wasm imports moon-component plug app.wasm library.wasm -o composed.wasm # Multiple plugs moon-component plug app.wasm lib1.wasm lib2.wasm -o composed.wasm

#moon-component compose <wac-file>

Compose multiple components using a WAC file (using wac compose).

moon-component compose composition.wac -o composed.wasm

Example WAC file (composition.wac):
package example:composed; let app = new app:component { ... }; let lib = new lib:component { ... }; // Wire lib exports to app imports let composed = new app { api: lib.api }; export composed...;

#moon-component bundle

Bundle components from a workspace config file. Automatically builds all components and composes them using WAC.

# Bundle using moon-component.toml moon-component bundle # Custom config file moon-component bundle -c my-config.toml # Only build components, don't compose moon-component bundle --build-only # Preview generated WAC without executing moon-component bundle --dry-run

#Bundle Configuration

Create moon-component.toml for declarative composition:

[bundle] name = "my/app" output = "dist/app.wasm" entry = "apps/main/component" # External imports (left unresolved for runtime) externals = ["wasi:io/*", "wasi:cli/*"] # Optional: use explicit WAC file instead of auto-generation # wac = "custom.wac" [dependencies] "mizchi:flatbuffers" = { path = "libs/flatbuffers/component" } "mizchi:json" = { path = "libs/json/component" } [build] target = "wasm" release = true

#How It Works

  1. Reads moon-component.toml
  2. Builds entry and all dependency components (parallel-ready)
  3. Auto-generates .wac file (or uses explicit one)
  4. Runs wac compose to create final component

#Generated WAC Example

package my:app:composed; let mizchi_flatbuffers = new mizchi:flatbuffers {}; let mizchi_json = new mizchi:json {}; let entry = new entry:component { "mizchi:flatbuffers": mizchi_flatbuffers."mizchi:flatbuffers", "mizchi:json": mizchi_json."mizchi:json", }; export entry...;

#Monorepo Component Composition

In a monorepo with multiple MoonBit libraries:

monorepo/ ├── moon-component.toml # Bundle config ├── libs/ │ ├── flatbuffers/component/ # flatbuffers component │ └── json/component/ # json component └── apps/ └── main/component/ # app that imports libs

# One command to build and compose everything moon-component bundle

#Manual Composition (Alternative)

For fine-grained control, you can use plug or compose directly:

# Build each component manually moon-component component libs/flatbuffers/wit/world.wit -o flatbuffers.wasm moon-component component apps/main/wit/world.wit -o main.wasm # Plug libraries into app moon-component plug main.wasm flatbuffers.wasm -o app.wasm # Or use WAC file for complex compositions moon-component compose composition.wac -o app.wasm

#Generated Directory Structure

component/ ├── moon.mod.json ├── wit/ │ └── world.wit # WIT definition ├── gen/ # Generated code (regenerated) │ └── cabi/ │ ├── moon.pkg.json │ └── cabi.mbt # Canonical ABI helpers └── impl/ # Implementation (preserved) ├── moon.pkg.json # is-main: true ├── bindings.mbt # Generated FFI glue (regenerated) └── impl.mbt # User implementation (stub, preserved)

  • gen/ - Regenerated on each generate call
  • impl/bindings.mbt - Regenerated (FFI glue)
  • impl/impl.mbt - Preserved (user implementation stub)
  • impl/moon.pkg.json - Preserved (user can add imports)

#Supported WIT Types

WIT TypeMoonBit TypeNotes
boolBool
u8Byte
u16, u32UInt
u64UInt64
s8, s16, s32Int
s64Int64
f32Float
f64Double
charChar
stringStringUTF-8 encoded
list<T>Array[T]
option<T>T?
result<T, E>Result[T, E]
tuple<...>(T1, T2, ...)
recordstruct
variantenum
enumenumWith from_ordinal/ordinal
flagsstruct (bitmask)With from_bits/to_bits
resourcestruct(Int)Handle-based (experimental)

#Resource Support (Experimental)

Resource types are supported with the following constraints:

For wasm-gc specifics, see docs/wasm-gc-component-resources.md.

#Constraints

  1. Handle-based only: Resources are represented as i32 handles (indices into a handle table)
  2. No borrow/own distinction: Both borrow<T> and own<T> are treated identically as handles
  3. No automatic lifetime management: Manual cleanup required (no finalizers in wasm-gc yet)
  4. MoonBit-side handle table: Resource data is managed in MoonBit, not by the host

#Example WIT

interface blob-store { resource blob { constructor(data: list<u8>); size: func() -> u32; read: func(offset: u32, len: u32) -> list<u8>; } create-blob: func(data: list<u8>) -> own<blob>; get-blob-size: func(b: borrow<blob>) -> u32; }

#Generated MoonBit Code

// Resource type (handle)

///|
pub(all) struct Blob(Int) derive(Show, Eq)

// Exported functions with normalized names

///|
pub fn blob_new(data : Array[Byte]) -> Blob // [constructor]blob
pub fn blob_size(this : Blob) -> UInt // [method]blob.size
pub fn blob_read(this : Blob, offset : UInt, len : UInt) -> Array[Byte]
pub fn create_blob(data : Array[Byte]) -> Blob
pub fn get_blob_size(b : Blob) -> UInt

#Implementation Pattern (Copy-based)

// Handle table for resource storage

///|
let blob_table : Ref[Array[Array[Byte]]] = { val: [] }

///|
fn allocate_blob(data : Array[Byte]) -> @exports.Blob {
let handle = blob_table.val.length()
blob_table.val.push(data)
@exports.Blob(handle)
}

///|
fn get_blob(handle : @exports.Blob) -> Array[Byte] {
blob_table.val[handle.0]
}

#Why Handle-based?

The WebAssembly Component Model specifies resources as opaque handles managed by a per-instance handle table. This approach:

  • Matches the Canonical ABI specification
  • Works with both wasm and wasm-gc targets
  • Allows future migration to native wasm-gc resource support when standardized

See Pre-Proposal: Wasm GC Support in Canonical ABI for ongoing standardization work.

#Examples

  • examples/hello - Basic string export
  • examples/reverse - String manipulation
  • examples/calc-impl - Calculator with records
  • examples/tests/types-test - All primitive and container types (MoonBit)
  • examples/tests/rust-guest - Reference implementation (Rust wit-bindgen)
  • examples/tests/zig-guest - Zig implementation using C bindings
  • examples/tests/resource-test - Resource type (experimental)

#Integration Tests

Host implementations for testing generated WebAssembly modules:

HostLanguageTest LevelNotes
examples/tests/rust-hostRustComponentFull canonical ABI testing via wasmtime
examples/tests/swift-hostSwiftCore WasmRuntime testing via WasmKit (macOS 14+)
examples/tests/scala-hostScalaCore WasmRuntime testing via Chicory (JDK 11+)
examples/tests/zig-hostZigCore WasmBinary format validation (export verification)
examples/tests/jco-hostJavaScriptComponentNode.js testing via jco transpiler

# Run all integration tests (Rust, Zig, Swift) just test-integration # Run all integration tests including Scala and jco (requires sbt, pnpm) just test-integration-all # Run individual host tests just test-rust-host just test-swift-host just test-scala-host just test-zig-host just test-jco-host

#
fib

fn fib(n : Int) -> Int64

#
sum

fn sum(data~ : Array[Int], start? : Int, length? : Int) -> Int

data is a labelled argument without default value having type Array[Int] start is an optional labelled argument with default value 0 having type Int length is an optional labelled argument without default value having type Option[Int]