github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/examples/multiple-results/multiple-results.go (about) 1 package main 2 3 import ( 4 "context" 5 _ "embed" 6 "fmt" 7 "log" 8 9 "github.com/bananabytelabs/wazero" 10 "github.com/bananabytelabs/wazero/api" 11 ) 12 13 // main implements functions with multiple returns values, using both an 14 // approach portable with any WebAssembly 1.0 runtime, as well one dependent 15 // on the "multiple-results" feature. 16 // 17 // The portable approach uses parameters to return additional results. The 18 // parameter value is a memory offset to write the next value. This is the same 19 // approach used by WASI. 20 // - resultOffsetWasmFunctions 21 // - resultOffsetHostFunctions 22 // 23 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md 24 // 25 // Another approach is to enable the "multiple-results" feature. While 26 // "multiple-results" is not yet a W3C recommendation, most WebAssembly 27 // runtimes support it by default, and it is include in the draft of 2.0. 28 // - multiValueWasmFunctions 29 // - multiValueHostFunctions 30 // 31 // See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md 32 func main() { 33 // Choose the context to use for function calls. 34 ctx := context.Background() 35 36 // Create a new WebAssembly Runtime. 37 r := wazero.NewRuntime(ctx) 38 defer r.Close(ctx) // This closes everything this Runtime created. 39 40 // Add a module that uses offset parameters for multiple results defined in WebAssembly. 41 wasm, err := resultOffsetWasmFunctions(ctx, r) 42 if err != nil { 43 log.Panicln(err) 44 } 45 46 // wazero enables WebAssembly Core Specification 2.0 features by default. 47 runtimeWithMultiValue := wazero.NewRuntime(ctx) 48 49 // Add a module that uses multiple results values 50 51 // ... defined in WebAssembly. 52 wasmWithMultiValue, err := multiValueWasmFunctions(ctx, runtimeWithMultiValue) 53 if err != nil { 54 log.Panicln(err) 55 } 56 57 // ... defined in Go. 58 multiValueFromImportedHost, err := multiValueFromImportedHostWasmFunctions(ctx, runtimeWithMultiValue) 59 if err != nil { 60 log.Panicln(err) 61 } 62 63 // Call the function from each module and print the results to the console. 64 for _, mod := range []api.Module{wasm, wasmWithMultiValue, multiValueFromImportedHost} { 65 getAge := mod.ExportedFunction("call_get_age") 66 results, err := getAge.Call(ctx) 67 if err != nil { 68 log.Panicln(err) 69 } 70 71 fmt.Printf("%s: age=%d\n", mod.Name(), results[0]) 72 } 73 } 74 75 // resultOffsetWasm was generated by the following: 76 // 77 // cd testdata; wat2wasm --debug-names result_offset.wat 78 // 79 //go:embed testdata/result_offset.wasm 80 var resultOffsetWasm []byte 81 82 // resultOffsetWasmFunctions are the WebAssembly equivalent of the Go-defined 83 // resultOffsetHostFunctions. The source is in testdata/result_offset.wat 84 func resultOffsetWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) { 85 return r.Instantiate(ctx, resultOffsetWasm) 86 } 87 88 // multiValueWasm was generated by the following: 89 // 90 // cd testdata; wat2wasm --debug-names multi_value.wat 91 // 92 //go:embed testdata/multi_value.wasm 93 var multiValueWasm []byte 94 95 // multiValueWasmFunctions are the WebAssembly equivalent of the Go-defined 96 // multiValueHostFunctions. The source is in testdata/multi_value.wat 97 func multiValueWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) { 98 return r.Instantiate(ctx, multiValueWasm) 99 } 100 101 // multiValueWasm was generated by the following: 102 // 103 // cd testdata; wat2wasm --debug-names multi_value_imported.wat 104 // 105 //go:embed testdata/multi_value_imported.wasm 106 var multiValueFromImportedHostWasm []byte 107 108 // multiValueFromImportedHostWasmFunctions return the WebAssembly which imports the Go-defined "get_age" function. 109 // The imported "get_age" function returns multiple results. The source is in testdata/multi_value_imported.wat 110 func multiValueFromImportedHostWasmFunctions(ctx context.Context, r wazero.Runtime) (api.Module, error) { 111 // Instantiate the host module with the exported `get_age` function which returns multiple results. 112 if _, err := r.NewHostModuleBuilder("multi-value/host"). 113 // Define a function that returns two results 114 NewFunctionBuilder(). 115 WithFunc(func(context.Context) (age uint64, errno uint32) { 116 age = 37 117 errno = 0 118 return 119 }). 120 Export("get_age"). 121 Instantiate(ctx); err != nil { 122 return nil, err 123 } 124 // Then, creates the module which imports the `get_age` function from the `multi-value/host` module above. 125 return r.Instantiate(ctx, multiValueFromImportedHostWasm) 126 }