github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/gojs/js.go (about)

     1  package gojs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/bananabytelabs/wazero/api"
     8  	"github.com/bananabytelabs/wazero/internal/gojs/goos"
     9  )
    10  
    11  // jsFn is a jsCall.call function, configured via jsVal.addFunction.
    12  //
    13  // Note: This is not a `func` because we need it to be a hashable type.
    14  type jsFn interface {
    15  	invoke(ctx context.Context, mod api.Module, args ...interface{}) (interface{}, error)
    16  }
    17  
    18  // jsCall allows calling a method/function by name.
    19  type jsCall interface {
    20  	call(ctx context.Context, mod api.Module, this goos.Ref, method string, args ...interface{}) (interface{}, error)
    21  }
    22  
    23  func newJsVal(ref goos.Ref, name string) *jsVal {
    24  	return &jsVal{ref: ref, name: name, properties: map[string]interface{}{}, functions: map[string]jsFn{}}
    25  }
    26  
    27  // jsVal corresponds to a generic js.Value in go, when `GOOS=js`.
    28  type jsVal struct {
    29  	// ref is the constant reference used for built-in values, such as
    30  	// objectConstructor.
    31  	ref        goos.Ref
    32  	name       string
    33  	properties map[string]interface{}
    34  	functions  map[string]jsFn
    35  }
    36  
    37  func (v *jsVal) addProperties(properties map[string]interface{}) *jsVal {
    38  	for k, val := range properties {
    39  		v.properties[k] = val
    40  	}
    41  	return v
    42  }
    43  
    44  func (v *jsVal) addFunction(method string, fn jsFn) *jsVal {
    45  	v.functions[method] = fn
    46  	// If fn returns an error, js.Call does a type lookup to verify it is a
    47  	// function.
    48  	// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L389
    49  	v.properties[method] = fn
    50  	return v
    51  }
    52  
    53  // Get implements the same method as documented on goos.GetFunction
    54  func (v *jsVal) Get(propertyKey string) interface{} {
    55  	if v, ok := v.properties[propertyKey]; ok {
    56  		return v
    57  	}
    58  	panic(fmt.Sprintf("TODO: get %s.%s", v.name, propertyKey))
    59  }
    60  
    61  // call implements jsCall.call
    62  func (v *jsVal) call(ctx context.Context, mod api.Module, this goos.Ref, method string, args ...interface{}) (interface{}, error) {
    63  	if v, ok := v.functions[method]; ok {
    64  		return v.invoke(ctx, mod, args...)
    65  	}
    66  	panic(fmt.Sprintf("TODO: call %s.%s", v.name, method))
    67  }
    68  
    69  // objectArray is a result of arrayConstructor typically used to pass
    70  // indexed arguments.
    71  //
    72  // Note: This is a wrapper because a slice is not hashable.
    73  type objectArray struct {
    74  	slice []interface{}
    75  }
    76  
    77  // object is a result of objectConstructor typically used to pass named
    78  // arguments.
    79  //
    80  // Note: This is a wrapper because a map is not hashable.
    81  type object struct {
    82  	properties map[string]interface{}
    83  }