Go (wazero host SDK)
The Go binding is a host SDK over the portable aozora.wasm Extism
plugin, run through the pure-Go wazero runtime.
There is no cgo and no native libextism to link — go get is the
whole install:
go get github.com/P4suta/aozora-go
It is one spoke of aozora’s polyglot binding strategy: rather than a
hand-written native binding per language, every non-Rust front door
funnels through the same aozora.wasm bytes and the same aozora::wire
authority. See Choosing a binding for when to reach for Go
versus the native C ABI or the in-process Rust library,
and Extism plugin for the wasm artifact this SDK loads. The
rationale for the whole approach is recorded in ADR-0006 (linked from the
crate README).
Install & quickstart
package main
import (
"context"
"fmt"
aozora "github.com/P4suta/aozora-go"
)
func main() {
ctx := context.Background()
p, err := aozora.Open(ctx)
if err != nil {
panic(err)
}
defer p.Close(ctx)
html, _ := p.ToHTML("|青梅《おうめ》")
fmt.Println(html) // <ruby>青梅<rt>おうめ</rt></ruby>
nodes, _ := p.Nodes("|青梅《おうめ》")
for _, n := range nodes.Data {
fmt.Printf("%s @ [%d,%d)\n", n.Kind, n.Span.Start, n.Span.End)
}
}
Open(ctx) instantiates the plugin once; reuse the returned Parser
across calls and Close(ctx) it when done. Beyond ToHTML and Nodes,
a Parser exposes Serialize, Diagnostics, Pairs, and
ContainerPairs — each returning the matching wire envelope decoded into
the generated Go types:
| Method | Returns | Notes |
|---|---|---|
ToHTML(src) | string | Semantic HTML5 with aozora-* class hooks. |
Serialize(src) | wire envelope | Canonical 青空文庫 source round-trip. |
Nodes(src) | wire envelope | Borrowed-AST nodes with Kind + Span. |
Diagnostics(src) | wire envelope | Same diagnostic schema as every other binding (see WASM → API surface). |
Pairs(src) | wire envelope | Matched ruby / bracket / quote pairs. |
ContainerPairs(src) | wire envelope | Matched indent / align-end container pairs. |
Concurrency
A Parser is not safe for concurrent use — the underlying Extism
instance carries per-call wasm linear-memory state. Open one Parser per
goroutine (each Open is independent), or guard a shared one behind your
own mutex. For parallel corpus processing the per-goroutine pattern is the
intended one; instances do not contend.
How it works
Open(ctx) loads the embedded aozora.wasm plugin into a fresh wazero
runtime. Every method serialises its argument, calls the corresponding
plugin export, and decodes the JSON envelope into a Go type. Those wire
types live in wire_gen.go and are generated by just types-langs
(quicktype, fed from the wire JSON Schema) — they are not hand-maintained,
so they cannot drift from the Rust aozora::wire definitions. Because the
plugin bytes and the wire schema are shared, the Go output is
byte-identical to the Rust, WASM, Python, and C-ABI front doors:
same HTML, same canonical serialisation, same diagnostics.
Building / contributing
From the aozora workspace root, just smoke-go builds the plugin
(just extism-build), embeds the resulting aozora.wasm into the module,
and runs gofmt + go vet + go test. The aozora.wasm artifact is
git-ignored locally and dropped in by that target or by the release
workflow; wire_gen.go is regenerated by just types-langs and must not
be edited by hand.
Reference
- aozora-go README — the canonical, deeper reference for the module layout, generated files, and the ADR-0006 link.
- Choosing a binding — Go vs. the other front doors.
- Extism plugin — the
aozora.wasmartifact this SDK drives. - WASM → API surface — the shared diagnostics JSON schema.