Skip to content

Commit

Permalink
Removed common.Bind
Browse files Browse the repository at this point in the history
  • Loading branch information
codebien committed Mar 10, 2022
1 parent 55c7ccd commit 2afe109
Show file tree
Hide file tree
Showing 11 changed files with 18 additions and 778 deletions.
7 changes: 3 additions & 4 deletions js/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ func (b *Bundle) Instantiate(
rt := vuImpl.runtime
bi = &BundleInstance{
Runtime: rt,
Context: vuImpl.ctxPtr,
Context: &vuImpl.ctx,
exports: make(map[string]goja.Callable),
env: b.RuntimeOptions.Env,
}
Expand Down Expand Up @@ -329,8 +329,7 @@ func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init *
Registry: b.registry,
}
init.moduleVUImpl.initEnv = initenv
ctx := common.WithInitEnv(context.Background(), initenv)
*init.moduleVUImpl.ctxPtr = common.WithRuntime(ctx, rt)
init.moduleVUImpl.ctx = context.Background()
unbindInit := common.BindToGlobal(rt, map[string]interface{}{
"require": init.Require,
"open": init.Open,
Expand All @@ -348,7 +347,7 @@ func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init *
return err
}
unbindInit()
*init.moduleVUImpl.ctxPtr = nil
init.moduleVUImpl.ctx = nil
init.moduleVUImpl.initEnv = nil

// If we've already initialized the original VU init context, forbid
Expand Down
152 changes: 0 additions & 152 deletions js/common/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ package common

import (
"context"
"fmt"
"reflect"
"strings"

Expand Down Expand Up @@ -132,154 +131,3 @@ func BindToGlobal(rt *goja.Runtime, data map[string]interface{}) func() {
}
}
}

// Bind the provided value v to the provided runtime
//
// Deprecated: JS modules can implement the modules.VU interface for getting the context,
// goja runtime and the VU State, so the goja.Runtime.Set method can be used for data binding.
func Bind(rt *goja.Runtime, v interface{}, ctxPtr *context.Context) map[string]interface{} {
exports := make(map[string]interface{})

val := reflect.ValueOf(v)
typ := val.Type()
for i := 0; i < typ.NumMethod(); i++ {
meth := typ.Method(i)
name := MethodName(typ, meth)
fn := val.Method(i)

// Figure out if we want to do any wrapping of it.
fnT := fn.Type()
numIn := fnT.NumIn()
numOut := fnT.NumOut()
hasError := (numOut > 1 && fnT.Out(1) == errorT)
wantsContext := false
wantsContextPtr := false
if numIn > 0 {
in0 := fnT.In(0)
switch in0 {
case ctxT:
wantsContext = true
case ctxPtrT:
wantsContextPtr = true
}
}
if hasError || wantsContext || wantsContextPtr {
isVariadic := fnT.IsVariadic()
realFn := fn
fn = reflect.ValueOf(func(call goja.FunctionCall) goja.Value {
// Number of arguments: the higher number between the function's required arguments
// and the number of arguments actually given.
args := make([]reflect.Value, numIn)

// Inject any requested parameters, and reserve them to offset user args.
reservedArgs := 0
if wantsContext {
if ctxPtr == nil || *ctxPtr == nil {
Throw(rt, fmt.Errorf("%s() can only be called from within default()", name))
}
args[0] = reflect.ValueOf(*ctxPtr)
reservedArgs++
} else if wantsContextPtr {
args[0] = reflect.ValueOf(ctxPtr)
reservedArgs++
}

// Copy over arguments.
for i := 0; i < numIn; i++ {
if i < reservedArgs {
continue
}

T := fnT.In(i)

// A function that takes a goja.FunctionCall takes only that arg (+ injected).
if T == fnCallT {
args[i] = reflect.ValueOf(call)
break
}

// The last arg to a varadic function is a slice of the remainder.
if isVariadic && i == numIn-1 {
varArgsLen := len(call.Arguments) - (i - reservedArgs)
if varArgsLen <= 0 {
args[i] = reflect.Zero(T)
break
}
varArgs := reflect.MakeSlice(T, varArgsLen, varArgsLen)
emT := T.Elem()
for j := 0; j < varArgsLen; j++ {
arg := call.Arguments[i+j-reservedArgs]
v := reflect.New(emT)
if err := rt.ExportTo(arg, v.Interface()); err != nil {
Throw(rt, err)
}
varArgs.Index(j).Set(v.Elem())
}
args[i] = varArgs
break
}

arg := call.Argument(i - reservedArgs)

// Optimization: no need to allocate a pointer and export for a zero value.
if goja.IsUndefined(arg) {
if T == jsValT {
args[i] = reflect.ValueOf(goja.Undefined())
continue
}
args[i] = reflect.Zero(T)
continue
}

// Allocate a T* and export the JS value to it.
v := reflect.New(T)
if err := rt.ExportTo(arg, v.Interface()); err != nil {
Throw(rt, err)
}
args[i] = v.Elem()
}

var ret []reflect.Value
if isVariadic {
ret = realFn.CallSlice(args)
} else {
ret = realFn.Call(args)
}

if len(ret) > 0 {
if hasError && !ret[1].IsNil() {
Throw(rt, ret[1].Interface().(error))
}
return rt.ToValue(ret[0].Interface())
}
return goja.Undefined()
})
}

// X-Prefixed methods are assumed to be constructors; use a closure to wrap them in a
// pure-JS function to allow them to be `new`d. (This is an awful hack...)
if meth.Name[0] == 'X' {
wrapperV, _ := rt.RunProgram(constructWrap)
wrapper, _ := goja.AssertFunction(wrapperV)
v, _ := wrapper(goja.Undefined(), rt.ToValue(fn.Interface()))
exports[name] = v
} else {
exports[name] = fn.Interface()
}
}

// If v is a pointer, we need to indirect it to access fields.
if typ.Kind() == reflect.Ptr {
val = val.Elem()
typ = val.Type()
}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
name := FieldName(typ, field)
if name != "" {
exports[name] = val.Field(i).Interface()
}
}

return exports
}
Loading

0 comments on commit 2afe109

Please sign in to comment.