Skip to content

Commit 91f6c48

Browse files
authored
Merge pull request #10 from jfleitz/add-core-functions
Adds wasi standard adapters to the go package
2 parents 51f28ec + c7a0859 commit 91f6c48

135 files changed

Lines changed: 25511 additions & 4 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
*.dll
88
*.so
99
*.dylib
10+
*.wasm
11+
12+
# Scratch directory used by regenerate_bindings.sh
13+
tmp/
1014

1115
# Test binary, built with `go test -c`
1216
*.test

.golangci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: "2"
2+
3+
linters:
4+
exclusions:
5+
# The wit-bindgen header ("Generated by `wit-bindgen` ... DO NOT EDIT!")
6+
# doesn't match the strict Go convention regex, so use the lenient
7+
# heuristic to skip the generated bindings in imports/ and exports/.
8+
generated: lenient

README.md

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div align="center">
22
<h1><code>go-pkg</code></h1>
33
<p>
4-
<strong>Golang packages for the Bytecode Alliance <a href="https://github.com/bytecodealliance/componentize-go">componentize-go</a> project</strong>
4+
<strong>The Go library for building WebAssembly components with <a href="https://github.com/bytecodealliance/componentize-go">componentize-go</a></strong>
55
</p>
66
<strong>A <a href="https://bytecodealliance.org/">Bytecode Alliance</a> project</strong>
77
<p>
@@ -15,13 +15,115 @@
1515

1616
# Overview
1717

18-
This is a set of Golang packages for the Bytecode Alliance componentize-go project.
18+
Module `go.bytecodealliance.org/pkg` is the Go library for Wasm components. It adapts standard-library interfaces (`net/http`, `log/slog`) to standard `wasi:*` interfaces and ships the committed bindings and WIT worlds needed to build HTTP components with [componentize-go](https://github.com/bytecodealliance/componentize-go). The use of this package significantly reduces the number of files generated and committed for a typical go application.
19+
20+
The library targets two worlds defined in [`wit/world.wit`](./wit/world.wit):
21+
22+
- **`bytecodealliance:pkg/wasip2`** (default): a sync WASI P2 component exporting `wasi:http/incoming-handler@0.2.8`, buildable with stock Go.
23+
- **`bytecodealliance:pkg/wasip3`** (opt-in): an async WASI P3 component exporting `wasi:http/handler@0.3.0` with streaming bodies and native concurrency.
24+
25+
## Packages
26+
27+
| Package | Description |
28+
| --- | --- |
29+
| `wasihttp` | `net/http` adapter for `wasi:http`: serve incoming requests with a standard `http.Handler` and send outbound requests through an `http.RoundTripper`. One API, two implementations selected by build tag (see below). |
30+
| `wasilog` | `slog.Handler` implementation over `wasi:logging`. |
31+
| `wasiconfig` | Helpers over `wasi:config/store`. |
32+
| `wit/types`, `wit/runtime`, `wit/async` | Core WIT value types (option, result, tuple, stream, future) and the canonical-ABI runtime support used by generated bindings. |
33+
| `imports/...` | Committed generated bindings for the `wasi:*` interfaces imported by the two worlds (both the 0.2.8 and 0.3.0 families). |
34+
| `exports/...` | Per-world generated `//go:wasmexport` glue and export trampolines. |
35+
36+
Bindings under `imports/` and `exports/` are generated by
37+
[`regenerate_bindings.sh`](./regenerate_bindings.sh) — do not edit them.
38+
39+
## Updating WIT dependencies
40+
41+
The `wasi:*` WIT packages under `wit/deps/` are vendored verbatim from the WebAssembly package registry using [wkg](https://github.com/bytecodealliance/wasm-pkg-tools). To update a dependency:
42+
43+
1. Bump its version in [`fetch_wit_deps.sh`](./fetch_wit_deps.sh) and in
44+
[`wit/world.wit`](./wit/world.wit).
45+
2. Re-fetch the vendored WIT:
46+
47+
```console
48+
$ ./fetch_wit_deps.sh
49+
```
50+
51+
3. Regenerate the committed bindings and commit everything together:
52+
53+
```console
54+
$ ./regenerate_bindings.sh
55+
```
56+
57+
> **Note**: the script uses `wkg get` with exact versions rather than
58+
> `wkg wit fetch` because the library intentionally depends on two versions
59+
> of several packages (e.g. `wasi:http@0.2.8` and `wasi:http@0.3.0`), and
60+
> `wkg wit fetch` resolves at most one version per package name.
61+
62+
## The `componentizego_async` build tag
63+
64+
`wasihttp` compiles to one of two implementations; the exported API is identical under both:
65+
66+
- **Default (no tag)**: sync WASI P2 (`wasi:http@0.2.8`). Matches the `bytecodealliance:pkg/wasip2` world.
67+
- **`-tags componentizego_async`**: async WASI P3 (`wasi:http@0.3.0`) with streaming bodies and native concurrency. Matches the `bytecodealliance:pkg/wasip3` world.
68+
69+
componentize-go sets the tag automatically when building an async world.
70+
71+
## Quickstart
72+
73+
```go
74+
package main
75+
76+
import (
77+
"net/http"
78+
79+
"go.bytecodealliance.org/pkg/wasihttp"
80+
)
81+
82+
func init() {
83+
wasihttp.HandleFunc(func(w http.ResponseWriter, r *http.Request) {
84+
w.Write([]byte("Hello, component!"))
85+
})
86+
}
87+
88+
func main() {}
89+
```
90+
91+
Add componentize-go as a Go tool and build:
92+
93+
```console
94+
$ go get -tool github.com/bytecodealliance/componentize-go
95+
$ go tool componentize-go build
96+
```
97+
98+
The default world (`bytecodealliance:pkg/wasip2@0.1.0`) is declared in [`componentize-go.toml`](./componentize-go.toml) and discovered automatically. To build the async WASI P3 world instead:
99+
100+
```console
101+
$ go tool componentize-go -w bytecodealliance:pkg/wasip3 build
102+
```
103+
104+
## Benchmarks
105+
106+
Pure-Go conversion logic (header conversion and friends) has microbenchmarks that run on the host:
107+
108+
```console
109+
$ go test -bench=. -benchmem ./...
110+
```
111+
112+
Packages that call `wasi:*` imports only link on wasm targets, so the benchmarks live in host-compilable packages (e.g. `internal/httpconv`).
113+
114+
For A/B comparisons use [benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat): collect ≥10 samples per side with the test filter disabled, then compare:
115+
116+
```console
117+
$ go test -bench=. -benchmem -count=10 -run='^$' ./... > old.txt
118+
$ # ... apply your change ...
119+
$ go test -bench=. -benchmem -count=10 -run='^$' ./... > new.txt
120+
$ benchstat old.txt new.txt
121+
```
19122

20123
## Questions?
21124

22125
Ask over in the Bytecode Alliance <a href="https://bytecodealliance.zulipchat.com">Zulip</a>.
23126

24127
## Contributing
25128

26-
See [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing
27-
to this repository.
129+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for more information about contributing to this repository.

componentize-go.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Default world for components built against this library. componentize-go
2+
# discovers this file via `go list -m all`, so `go tool componentize-go
3+
# build` needs no flags in consuming apps.
4+
#
5+
# The default is the sync WASI P2 world, which builds with stock Go. To
6+
# target the async WASI P3 world instead, build with:
7+
# componentize-go -w bytecodealliance:pkg/wasip3 build
8+
worlds = ["bytecodealliance:pkg/wasip2@0.1.0"]
9+
wit_paths = ["wit"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Package export_wasi_http_0_2_8_incoming_handler is the export trampoline
2+
// for the sync `wasip2` world's `wasi:http/incoming-handler@0.2.8` export.
3+
// The generated wit_exports glue calls Handle; the library's wasihttp
4+
// package assigns Exports.Handle at init time.
5+
package export_wasi_http_0_2_8_incoming_handler
6+
7+
import (
8+
"go.bytecodealliance.org/pkg/imports/wasi_http_0_2_8_types"
9+
)
10+
11+
var Exports struct {
12+
Handle func(request *wasi_http_0_2_8_types.IncomingRequest, responseOut *wasi_http_0_2_8_types.ResponseOutparam)
13+
}
14+
15+
func Handle(request *wasi_http_0_2_8_types.IncomingRequest, responseOut *wasi_http_0_2_8_types.ResponseOutparam) {
16+
Exports.Handle(request, responseOut)
17+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// This file exists for testing this package without WebAssembly,
2+
// allowing empty function bodies with a //go:wasmimport directive.
3+
// See https://pkg.go.dev/cmd/compile for more information.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Generated by `wit-bindgen` 0.59.0. DO NOT EDIT!
2+
//
3+
// This code was generated from the following packages:
4+
// wasi:io@0.2.8
5+
// wasi:clocks@0.2.8
6+
// wasi:filesystem@0.2.8
7+
// wasi:sockets@0.2.8
8+
// wasi:random@0.2.8
9+
// wasi:cli@0.2.8
10+
// wasi:config@0.2.0-rc.1
11+
// wasi:logging@0.1.0-draft
12+
// wasi:http@0.2.8
13+
// wasi:clocks@0.3.0
14+
// wasi:filesystem@0.3.0
15+
// wasi:sockets@0.3.0
16+
// wasi:random@0.3.0
17+
// wasi:cli@0.3.0
18+
// wasi:http@0.3.0
19+
// bytecodealliance:pkg@0.1.0
20+
21+
package wit_exports
22+
23+
import (
24+
"go.bytecodealliance.org/pkg/exports/bytecodealliance_pkg_wasip2_0_1_0/export_wasi_http_0_2_8_incoming_handler"
25+
"go.bytecodealliance.org/pkg/imports/wasi_http_0_2_8_types"
26+
witRuntime "go.bytecodealliance.org/pkg/wit/runtime"
27+
"runtime"
28+
)
29+
30+
var staticPinner = runtime.Pinner{}
31+
var exportReturnArea = uintptr(witRuntime.Allocate(&staticPinner, 0, 1))
32+
var syncExportPinner = runtime.Pinner{}
33+
34+
//go:wasmexport wasi:http/incoming-handler@0.2.8#handle
35+
func wasm_export_wasi_http_0_2_8_incoming_handler_handle(arg0 int32, arg1 int32) {
36+
37+
export_wasi_http_0_2_8_incoming_handler.Handle(wasi_http_0_2_8_types.IncomingRequestFromOwnHandle(int32(uintptr(arg0))), wasi_http_0_2_8_types.ResponseOutparamFromOwnHandle(int32(uintptr(arg1))))
38+
39+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Package export_wasi_http_0_3_0_handler is the export trampoline for the
2+
// async `wasip3` world's `wasi:http/handler@0.3.0` export. The generated
3+
// wit_exports glue calls Handle; the library's wasihttp package assigns
4+
// Exports.Handle at init time.
5+
package export_wasi_http_0_3_0_handler
6+
7+
import (
8+
"go.bytecodealliance.org/pkg/imports/wasi_http_0_3_0_types"
9+
witTypes "go.bytecodealliance.org/pkg/wit/types"
10+
)
11+
12+
var Exports struct {
13+
Handle func(request *wasi_http_0_3_0_types.Request) witTypes.Result[*wasi_http_0_3_0_types.Response, wasi_http_0_3_0_types.ErrorCode]
14+
}
15+
16+
func Handle(request *wasi_http_0_3_0_types.Request) witTypes.Result[*wasi_http_0_3_0_types.Response, wasi_http_0_3_0_types.ErrorCode] {
17+
return Exports.Handle(request)
18+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// This file exists for testing this package without WebAssembly,
2+
// allowing empty function bodies with a //go:wasmimport directive.
3+
// See https://pkg.go.dev/cmd/compile for more information.

0 commit comments

Comments
 (0)