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 }