wa-lang.org/wazero@v1.0.2/examples/namespace/counter.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"fmt"
     7  	"log"
     8  
     9  	"wa-lang.org/wazero"
    10  	"wa-lang.org/wazero/api"
    11  )
    12  
    13  // counterWasm was generated by the following:
    14  //
    15  //	cd testdata; wat2wasm --debug-names counter.wat
    16  //
    17  //go:embed testdata/counter.wasm
    18  var counterWasm []byte
    19  
    20  // main shows how to instantiate the same module name multiple times in the same runtime.
    21  //
    22  // See README.md for a full description.
    23  func main() {
    24  	// Choose the context to use for function calls.
    25  	ctx := context.Background()
    26  
    27  	// Create a new WebAssembly Runtime.
    28  	r := wazero.NewRuntime(ctx)
    29  	defer r.Close(ctx) // This closes everything this Runtime created.
    30  
    31  	// Compile WebAssembly that requires its own "env" module.
    32  	compiled, err := r.CompileModule(ctx, counterWasm)
    33  	if err != nil {
    34  		log.Panicln(err)
    35  	}
    36  
    37  	// Instantiate two modules, with identical configuration, but independent state.
    38  	m1 := instantiateWithEnv(ctx, r, compiled)
    39  	m2 := instantiateWithEnv(ctx, r, compiled)
    40  
    41  	for i := 0; i < 2; i++ {
    42  		fmt.Printf("m1 counter=%d\n", counterGet(ctx, m1))
    43  		fmt.Printf("m2 counter=%d\n", counterGet(ctx, m2))
    44  	}
    45  }
    46  
    47  // count calls "counter.get" in the given namespace
    48  func counterGet(ctx context.Context, mod api.Module) uint64 {
    49  	results, err := mod.ExportedFunction("get").Call(ctx)
    50  	if err != nil {
    51  		log.Panicln(err)
    52  	}
    53  	return results[0]
    54  }
    55  
    56  // counter is an example showing state that needs to be independent per importing module.
    57  type counter struct {
    58  	counter uint32
    59  }
    60  
    61  func (e *counter) getAndIncrement() (ret uint32) {
    62  	ret = e.counter
    63  	e.counter++
    64  	return
    65  }
    66  
    67  // instantiateWithEnv returns a module instantiated with its own "env" module.
    68  func instantiateWithEnv(ctx context.Context, r wazero.Runtime, module wazero.CompiledModule) api.Module {
    69  	// Create a new namespace to instantiate modules into.
    70  	ns := r.NewNamespace(ctx) // Note: this is closed when the Runtime is
    71  
    72  	// Instantiate a new "env" module which exports a stateful function.
    73  	c := &counter{}
    74  	_, err := r.NewHostModuleBuilder("env").
    75  		NewFunctionBuilder().WithFunc(c.getAndIncrement).Export("next_i32").
    76  		Instantiate(ctx, ns)
    77  	if err != nil {
    78  		log.Panicln(err)
    79  	}
    80  
    81  	// Instantiate the module that imports "env".
    82  	mod, err := ns.InstantiateModule(ctx, module, wazero.NewModuleConfig())
    83  	if err != nil {
    84  		log.Panicln(err)
    85  	}
    86  
    87  	return mod
    88  }