Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: generate export bindings #65

Closed
ydnar opened this issue Mar 8, 2024 · 0 comments
Closed

proposal: generate export bindings #65

ydnar opened this issue Mar 8, 2024 · 0 comments
Assignees

Comments

@ydnar
Copy link
Owner

ydnar commented Mar 8, 2024

This document describes a design and mechanism for generated Go bindings for Component Model exports.

Background

The Component Model describes a mechanism for a WebAssembly program to export functions and methods that adhere to a specific WIT world (an API contract).

WIT worlds can export whole interfaces (e.g. wasi:cli/command) or individual functions. A WIT interface contains freestanding functions and types, which can include resource types with methods.

Exports are currently declared in a WIT file with a world that has one or more export directives, which export either an entire WIT interface or an individual function. This document presumes the existence of //go:wasmexport or similar (e.g. //export in TinyGo) to expose exported symbols in the resulting WebAssembly binary.

The design proposed here is similar to the approach taken by wit-bindgen, which generates Go bindings on top of Cgo suitable for TinyGo.

TODO: add more context

Proposed Design

For each exported function and method, wit-bindgen-go would generate a corresponding Go function with the relevant //go:wasmexport directive. The generated function would call a user-provided function. If the user-provided function is undefined (nil), the program will panic.

The expectation is that user code would import a generated Go package and call an Export() function or similar to register its implementation of the required interface(s).

Exported Interfaces

For each WIT interface, create a Go package-level exports interface type named Exports, containing one Go method for each freestanding WIT function in the WIT interface, a Go method to map resource handles to a Go interface (more below), and any resource constructor(s) or static function(s) if present.

// Exports represents the exported interface "wasi:filesystem/types".
type Exports interface {
    // freestanding functions
    // resource types
    // resource constructors and static methods
}

For each resource type defined in the WIT interface, an additional Go resource interface would be defined:

// DescriptorInterface represents the exported resource "wasi:filesystem/types#descriptor".
type DescriptorInterface interface {
    // resource methods
    // TODO: ResourceDrop, ResourceRep, and other administrative functions
}

For each resource type, a Go method is added to the exports interface with the name of the resource type, to translate an opaque handle value (i32) to the resource interface, along with constructor(s) and static methods:

// Exports represents the exported interface "wasi:filesystem/types".
type Exports interface {
    // Descriptor maps a handle to an exported DescriptorInterface.
    Descriptor(handle Descriptor) DescriptorInterface

    // NewDescriptor represents the exported constructor for `wasi:filesystem/types#descriptor".
    NewDescriptor() Descriptor
}

Usage

In order for a Go program to satisfy the runtime requirements of its component exports, user code must implement the exports interface by creating a exports implementation type with methods that match the exports interface:

package main

import "wasi/filesystem/types"

func init() {
    types.Export(&FilesystemExports{})
}

type FilesystemExports struct{}

func (e *FilesystemExports) Descriptor(handle types.Descriptor) DescriptorInterface {
    // TODO: use Component Model resource rep to return pointer
}

func (e *FilesystemExports) NewDescriptor() types.Descriptor {
    // ...
}

type Descriptor struct { /* ... */ }

func (d *Descriptor) Destructor() { /* ... */ }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant