Sign in

    wit.mbt

    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    8 months ago
    Downloads
    31

    Dependencies

    #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]