wasm-tools-go
wasm-tools-go copied to clipboard
proposal: generate export bindings
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() { /* ... */ }