splicer 2.3.0

Plan and generate middleware splice operations for WebAssembly component composition graphs.
Documentation
/// Shared types used across all splicer middleware tiers.
///
/// Tier WIT packages (`splicer:tier1`, `splicer:tier2`, ...) import
/// types defined here so the call-identity and lifted-value shapes
/// stay consistent across tiers as middleware authors move up.
package splicer:common@0.2.0;

interface types {
    /// Identity of the wrapped call: target interface
    /// (e.g. `"wasi:http/handler@0.3.0"`), canonical-ABI function
    /// name (e.g. `"handle"`, `"[method]request.body"`), and a
    /// monotonic per-instance id for correlating `on-call` /
    /// `on-return` of the same invocation.
    record call-id {
        interface-name: string,
        function-name: string,
        id: u64,
    }

    // ── Lifted-value representation ───────────────────────────────
    //
    // Each canonical-ABI value gets lifted into a `field-tree`:
    // a flat array of cells plus side tables for any nominal-typed
    // information, plus an index identifying the root.
    //
    // Compound cells reference children by `u32` index into the
    // same cells array. Why index-based recursion instead of a
    // self-referential variant? WIT does not yet support recursive
    // types — see
    // https://github.com/WebAssembly/component-model/issues/56.
    //
    // ── Cell sizing ───────────────────────────────────────────────
    //
    // Why is every nominal-typed case (record-of, variant-case,
    // handle, etc.) just a `u32`? Canonical-ABI lays out a list of
    // variant elements as fixed-stride memory, where the stride
    // equals the variant's max payload size padded to alignment.
    // If we kept type-names + field metadata inline in those cases,
    // every cell — even a `cell::bool(true)` — would pay 24+ bytes
    // of padding. Pulling the metadata out into per-kind side tables
    // (record-infos, variant-infos, etc.) caps every cell payload at
    // 8 bytes (s64), so the cell stride lands at 16 bytes.
    //
    // Trade-off: middleware code needs one extra lookup
    // (`tree.record_infos[idx]`) for nominal cases. Helper libraries
    // hide this; the wire savings (~50% on cells in primitive-
    // dominated trees) make it worth the small ergonomic cost.

    /// `record { ... }` payload — type name + named fields, where each
    /// field references a child cell by index.
    record record-info {
        type-name: string,
        /// `(field-name, cell-index)` per declared field, in WIT order.
        fields: list<tuple<string, u32>>,
    }

    /// `flags { ... }` payload — type name + names of set bits.
    record flags-info {
        type-name: string,
        set-flags: list<string>,
    }

    /// `enum { ... }` payload — type name + the case-name in this value.
    record enum-info {
        type-name: string,
        case-name: string,
    }

    /// `variant { ... }` payload — type name, case name, optional payload index.
    record variant-info {
        type-name: string,
        case-name: string,
        /// Index of the payload cell, or `none` for payload-less cases.
        payload: option<u32>,
    }

    /// `own<R>` / `borrow<R>` / `stream<T>` / `future<T>` /
    /// `error-context` payload — resource (or element) type name +
    /// opaque correlation id. The id is **not** a usable handle;
    /// the adapter still owns canonical-ABI ownership semantics.
    /// Useful for correlating the same handle's appearances across
    /// multiple calls. For `error-context-handle` the `type-name`
    /// is empty — the cell-disc already names the kind, and there
    /// is no nested type to surface.
    record handle-info {
        type-name: string,
        id: u64,
    }

    /// One node in a lifted value tree. Compound cases hold either a
    /// `u32` cell-index (for structural recursion) or a `u32` side-
    /// table index (for nominal metadata).
    variant cell {
        // ── primitives — payload fits in 8 bytes ──────────────────
        %bool(bool),
        integer(s64),                          // s8/s16/s32/s64/u8/u16/u32/u64
        floating(f64),                         // f32/f64 (widened)
        text(string),                          // string and char
        bytes(list<u8>),                       // list<u8> fast-path

        // ── structural / anonymous types — index into cells ───────
        list-of(list<u32>),                    // child indices, in order
        tuple-of(list<u32>),                   // child indices, in order
        option-some(u32),                      // index of inner value
        option-none,
        result-ok(option<u32>),                // index, or none for unit ok
        result-err(option<u32>),               // index, or none for unit err

        // ── nominal types — index into the corresponding side table
        record-of(u32),                        // → record-infos[idx]
        flags-set(u32),                        // → flags-infos[idx]
        enum-case(u32),                        // → enum-infos[idx]
        variant-case(u32),                     // → variant-infos[idx]

        // ── opaque correlation handles — index into handle-infos ──
        resource-handle(u32),                  // → handle-infos[idx]
        stream-handle(u32),                    // → handle-infos[idx]
        future-handle(u32),                    // → handle-infos[idx]
        // `error-context` is lifted as just an opaque id — the canonical-ABI
        // `error-context.debug-message` builtin would let us surface the
        // string, but cross-component error-context lift is currently broken
        // in wasmtime (<=44, "very incomplete" per its own config docstring),
        // so the wrapper never gets to call it. Revisit when host catches up.
        error-context-handle(u32),             // → handle-infos[idx]
    }

    /// A lifted value tree: a flat array of cells, side tables for
    /// nominal-typed information, plus the root cell index. Walk by
    /// reading `cells[root]` and following child indices for
    /// compound cases (or side-table indices for nominal cases).
    record field-tree {
        cells: list<cell>,
        record-infos:  list<record-info>,
        flags-infos:   list<flags-info>,
        enum-infos:    list<enum-info>,
        variant-infos: list<variant-info>,
        handle-infos:  list<handle-info>,
        root: u32,
    }

    /// Named slot in a function's argument list.
    record field {
        name: string,
        tree: field-tree,
    }
}