Repository: tetratelabs/wazero
Pull request #814 (2022-09-28 07:34:15)

Adds MustInstantiate to host imports
This adds an easier interface to those configuring infrastructural host imports such as WASI, and never unloading them except as a side effect of closing the runtime.

Ex.
```diff
-       if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-               log.Panicln(err)
-       }
+       wasi_snapshot_preview1.MustInstantiate(ctx, r)
```


Patch:
diff --git a/builder.go b/builder.go
index 45df2493..214a7838 100644
--- a/builder.go
+++ b/builder.go
@@ -137,6 +137,7 @@ type HostModuleBuilder interface {
 	Compile(context.Context) (CompiledModule, error)
 
 	// Instantiate is a convenience that calls Compile, then Namespace.InstantiateModule.
+	// This can fail for reasons documented on Namespace.InstantiateModule.
 	//
 	// Ex.
 	//
diff --git a/examples/allocation/tinygo/greet.go b/examples/allocation/tinygo/greet.go
index d0c222e5..63056bed 100644
--- a/examples/allocation/tinygo/greet.go
+++ b/examples/allocation/tinygo/greet.go
@@ -40,9 +40,7 @@ func main() {
 
 	// Note: testdata/greet.go doesn't use WASI, but TinyGo needs it to
 	// implement functions such as panic.
-	if _, err = wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Instantiate a WebAssembly module that imports the "log" function defined
 	// in "env" and exports "memory" and functions we'll use in this example.
diff --git a/examples/basic/add.go b/examples/basic/add.go
index d45c69cd..e1a0e06a 100644
--- a/examples/basic/add.go
+++ b/examples/basic/add.go
@@ -34,9 +34,7 @@ func main() {
 
 	// Instantiate WASI, which implements host functions needed for TinyGo to
 	// implement `panic`.
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Instantiate the guest Wasm into the same runtime. It exports the `add`
 	// function, implemented in WebAssembly.
diff --git a/imports/assemblyscript/assemblyscript.go b/imports/assemblyscript/assemblyscript.go
index 668114b5..f6120964 100644
--- a/imports/assemblyscript/assemblyscript.go
+++ b/imports/assemblyscript/assemblyscript.go
@@ -45,11 +45,22 @@ const (
 	functionSeed  = "seed"
 )
 
+// MustInstantiate calls Instantiate or panics on error.
+//
+// This is a simpler function for those who know the module "env" is not
+// already instantiated, and don't need to unload it.
+func MustInstantiate(ctx context.Context, r wazero.Runtime) {
+	if _, err := Instantiate(ctx, r); err != nil {
+		panic(err)
+	}
+}
+
 // Instantiate instantiates the "env" module used by AssemblyScript into the
 // runtime default namespace.
 //
 // # Notes
 //
+//   - Failure cases are documented on wazero.Namespace InstantiateModule.
 //   - Closing the wazero.Runtime has the same effect as closing the result.
 //   - To add more functions to the "env" module, use FunctionExporter.
 //   - To instantiate into another wazero.Namespace, use FunctionExporter.
diff --git a/imports/emscripten/emscripten.go b/imports/emscripten/emscripten.go
index bd7b0676..38fb0ea0 100644
--- a/imports/emscripten/emscripten.go
+++ b/imports/emscripten/emscripten.go
@@ -20,11 +20,22 @@ import (
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
+// MustInstantiate calls Instantiate or panics on error.
+//
+// This is a simpler function for those who know the module "env" is not
+// already instantiated, and don't need to unload it.
+func MustInstantiate(ctx context.Context, r wazero.Runtime) {
+	if _, err := Instantiate(ctx, r); err != nil {
+		panic(err)
+	}
+}
+
 // Instantiate instantiates the "env" module used by Emscripten into the
 // runtime default namespace.
 //
 // # Notes
 //
+//   - Failure cases are documented on wazero.Namespace InstantiateModule.
 //   - Closing the wazero.Runtime has the same effect as closing the result.
 //   - To add more functions to the "env" module, use FunctionExporter.
 //   - To instantiate into another wazero.Namespace, use FunctionExporter.
diff --git a/imports/wasi_snapshot_preview1/example/cat.go b/imports/wasi_snapshot_preview1/example/cat.go
index 564e36b4..79db3426 100644
--- a/imports/wasi_snapshot_preview1/example/cat.go
+++ b/imports/wasi_snapshot_preview1/example/cat.go
@@ -57,9 +57,7 @@ func main() {
 		WithStdout(os.Stdout).WithStderr(os.Stderr).WithFS(rooted)
 
 	// Instantiate WASI, which implements system I/O such as console output.
-	if _, err = wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Choose the binary we want to test. Most compilers that implement WASI
 	// are portable enough to use binaries interchangeably.
diff --git a/imports/wasi_snapshot_preview1/wasi.go b/imports/wasi_snapshot_preview1/wasi.go
index fc1d6fd3..ec113b77 100644
--- a/imports/wasi_snapshot_preview1/wasi.go
+++ b/imports/wasi_snapshot_preview1/wasi.go
@@ -10,7 +10,7 @@
 //	r := wazero.NewRuntime(ctx)
 //	defer r.Close(ctx) // This closes everything this Runtime created.
 //
-//	_, _ = Instantiate(ctx, r)
+//	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 //	mod, _ := r.InstantiateModuleFromBinary(ctx, wasm)
 //
 // See https://github.com/WebAssembly/WASI
@@ -30,11 +30,22 @@ import (
 const ModuleName = "wasi_snapshot_preview1"
 const i32, i64 = wasm.ValueTypeI32, wasm.ValueTypeI64
 
+// MustInstantiate calls Instantiate or panics on error.
+//
+// This is a simpler function for those who know the module ModuleName is not
+// already instantiated, and don't need to unload it.
+func MustInstantiate(ctx context.Context, r wazero.Runtime) {
+	if _, err := Instantiate(ctx, r); err != nil {
+		panic(err)
+	}
+}
+
 // Instantiate instantiates the ModuleName module into the runtime default
-// namespace.
+// namespace..
 //
 // # Notes
 //
+//   - Failure cases are documented on wazero.Namespace InstantiateModule.
 //   - Closing the wazero.Runtime has the same effect as closing the result.
 //   - To instantiate into another wazero.Namespace, use NewBuilder instead.
 func Instantiate(ctx context.Context, r wazero.Runtime) (api.Closer, error) {


Test patch:
diff --git a/example_test.go b/example_test.go
index ea9a0b5a..7143826c 100644
--- a/example_test.go
+++ b/example_test.go
@@ -35,9 +35,7 @@ func Example() {
 
 	// Instantiate WASI, which implements host functions needed for TinyGo to
 	// implement `panic`.
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Instantiate the guest Wasm into the same runtime. It exports the `add`
 	// function, implemented in WebAssembly.
diff --git a/experimental/fs_example_test.go b/experimental/fs_example_test.go
index 948b33b4..b5623e4f 100644
--- a/experimental/fs_example_test.go
+++ b/experimental/fs_example_test.go
@@ -27,9 +27,7 @@ func Example_withFS() {
 	r := wazero.NewRuntime(ctx)
 	defer r.Close(ctx) // This closes everything this Runtime created.
 
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Instantiate a module exporting a WASI function that uses the filesystem.
 	mod, err := r.InstantiateModuleFromBinary(ctx, fsWasm)
diff --git a/experimental/listener_example_test.go b/experimental/listener_example_test.go
index 12e0a03c..90475859 100644
--- a/experimental/listener_example_test.go
+++ b/experimental/listener_example_test.go
@@ -61,9 +61,7 @@ func Example_customListenerFactory() {
 	r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
 	defer r.Close(ctx) // This closes everything this Runtime created.
 
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Compile the WebAssembly module using the default configuration.
 	code, err := r.CompileModule(ctx, listenerWasm, wazero.NewCompileConfig())
diff --git a/experimental/logging/log_listener_example_test.go b/experimental/logging/log_listener_example_test.go
index fdcd27ca..6b381b04 100644
--- a/experimental/logging/log_listener_example_test.go
+++ b/experimental/logging/log_listener_example_test.go
@@ -27,9 +27,7 @@ func Example_newLoggingListenerFactory() {
 	r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
 	defer r.Close(ctx) // This closes everything this Runtime created.
 
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Compile the WebAssembly module using the default configuration.
 	code, err := r.CompileModule(ctx, listenerWasm, wazero.NewCompileConfig())
diff --git a/imports/assemblyscript/assemblyscript_example_test.go b/imports/assemblyscript/assemblyscript_example_test.go
index 7a107ae4..5c046123 100644
--- a/imports/assemblyscript/assemblyscript_example_test.go
+++ b/imports/assemblyscript/assemblyscript_example_test.go
@@ -3,7 +3,6 @@ package assemblyscript_test
 import (
 	"context"
 	_ "embed"
-	"log"
 
 	"github.com/tetratelabs/wazero"
 	"github.com/tetratelabs/wazero/imports/assemblyscript"
@@ -18,9 +17,7 @@ func Example_instantiate() {
 
 	// This adds the "env" module to the runtime, with AssemblyScript's special
 	// function imports.
-	if _, err := assemblyscript.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	assemblyscript.MustInstantiate(ctx, r)
 
 	// Output:
 }
diff --git a/imports/emscripten/emscripten_example_test.go b/imports/emscripten/emscripten_example_test.go
index 50e35619..1baf3790 100644
--- a/imports/emscripten/emscripten_example_test.go
+++ b/imports/emscripten/emscripten_example_test.go
@@ -3,7 +3,6 @@ package emscripten_test
 import (
 	"context"
 	_ "embed"
-	"log"
 
 	"github.com/tetratelabs/wazero"
 	"github.com/tetratelabs/wazero/imports/emscripten"
@@ -18,14 +17,10 @@ func Example_instantiate() {
 	defer r.Close(ctx) // This closes everything this Runtime created.
 
 	// Add WASI which is typically required when using Emscripten.
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Now, add the "env" module to the runtime, Emscripten default imports.
-	if _, err := emscripten.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	emscripten.MustInstantiate(ctx, r)
 
 	// Output:
 }
@@ -39,9 +34,7 @@ func Example_functionExporter() {
 	defer r.Close(ctx) // This closes everything this Runtime created.
 
 	// Add WASI which is typically required when using Emscripten.
-	if _, err := wasi_snapshot_preview1.Instantiate(ctx, r); err != nil {
-		log.Panicln(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
 	// Next, construct your own module builder for "env" with any functions
 	// you need.
diff --git a/imports/emscripten/emscripten_test.go b/imports/emscripten/emscripten_test.go
index efb65617..4dd3d675 100644
--- a/imports/emscripten/emscripten_test.go
+++ b/imports/emscripten/emscripten_test.go
@@ -32,10 +32,9 @@ func TestGrow(t *testing.T) {
 	r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())
 	defer r.Close(ctx)
 
-	_, err := wasi_snapshot_preview1.Instantiate(ctx, r)
-	require.NoError(t, err)
+	wasi_snapshot_preview1.MustInstantiate(ctx, r)
 
-	_, err = Instantiate(ctx, r)
+	_, err := Instantiate(ctx, r)
 	require.NoError(t, err)
 
 	// Emscripten exits main with zero by default
diff --git a/internal/integration_test/bench/bench_test.go b/internal/integration_test/bench/bench_test.go
index bd7bdebc..234203b5 100644
--- a/internal/integration_test/bench/bench_test.go
+++ b/internal/integration_test/bench/bench_test.go
@@ -224,9 +224,6 @@ func createRuntime(b *testing.B, config wazero.RuntimeConfig) wazero.Runtime {
 
 	// Note: host_func.go doesn't directly use WASI, but TinyGo needs to be initialized as a WASI Command.
 	// Add WASI to satisfy import tests
-	_, err = wasi_snapshot_preview1.Instantiate(testCtx, r)
-	if err != nil {
-		b.Fatal(err)
-	}
+	wasi_snapshot_preview1.MustInstantiate(testCtx, r)
 	return r
 }
diff --git a/internal/integration_test/bench/codec_test.go b/internal/integration_test/bench/codec_test.go
index b6a1f44d..52a66ab1 100644
--- a/internal/integration_test/bench/codec_test.go
+++ b/internal/integration_test/bench/codec_test.go
@@ -96,16 +96,14 @@ func TestExampleUpToDate(t *testing.T) {
 
 	t.Run("Executable", func(t *testing.T) {
 		r := wazero.NewRuntimeWithConfig(testCtx, wazero.NewRuntimeConfig())
+		defer r.Close(testCtx)
 
 		// Add WASI to satisfy import tests
-		wm, err := wasi_snapshot_preview1.Instantiate(testCtx, r)
-		require.NoError(t, err)
-		defer wm.Close(testCtx)
+		wasi_snapshot_preview1.MustInstantiate(testCtx, r)
 
 		// Decode and instantiate the module
 		module, err := r.InstantiateModuleFromBinary(testCtx, exampleWasm)
 		require.NoError(t, err)
-		defer module.Close(testCtx)
 
 		// Call the swap function as a smoke test
 		results, err := module.ExportedFunction("swap").Call(testCtx, 1, 2)
diff --git a/internal/integration_test/fs/fs_test.go b/internal/integration_test/fs/fs_test.go
index ca0a349e..98d233ef 100644
--- a/internal/integration_test/fs/fs_test.go
+++ b/internal/integration_test/fs/fs_test.go
@@ -152,8 +152,7 @@ func TestReader(t *testing.T) {
 	r := wazero.NewRuntime(testCtx)
 	defer r.Close(testCtx)
 
-	_, err := wasi_snapshot_preview1.Instantiate(testCtx, r)
-	require.NoError(t, err)
+	wasi_snapshot_preview1.MustInstantiate(testCtx, r)
 
 	realFs := fstest.MapFS{"animals.txt": &fstest.MapFile{Data: animals}}
 	sys := wazero.NewModuleConfig().WithFS(realFs)