Skip to content

Commit

Permalink
Added support for creating objects in golang function callbacks.
Browse files Browse the repository at this point in the history
  • Loading branch information
teuget committed Jun 18, 2021
1 parent 76db6dd commit 88d85ab
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 0 deletions.
6 changes: 6 additions & 0 deletions object.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ type Object struct {
*Value
}

// Instantiate a new blank object without any properties.
// Add properties on the object using Set.
func NewObject(ctx *Context) *Object {
return &Object{&Value{C.NewObject(ctx.iso.ptr), ctx}}
}

// Set will set a property on the Object to a given value.
// Supports all value types, eg: Object, Array, Date, Set, Map etc
// If the value passed is a Go supported primitive (string, int32, uint32, int64, uint64, float64, big.Int)
Expand Down
96 changes: 96 additions & 0 deletions object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
package v8go_test

import (
"errors"
"fmt"
"log"
"testing"

"rogchap.com/v8go"
Expand Down Expand Up @@ -114,3 +116,97 @@ func ExampleObject_global() {
// Output:
// foo
}

type objectTester struct{}

func (a *objectTester) GetCreateObjectFunctionCallback() v8go.FunctionCallback {
return func(info *v8go.FunctionCallbackInfo) *v8go.Value {
iso, err := info.Context().Isolate()
if err != nil {
log.Fatalf("Could not get isolate from context: %v\n", err)
}
args := info.Args()
if len(args) != 2 {
return iso.ThrowException("Function CreateObject expects 2 parameters")
}
if !args[0].IsInt32() || !args[1].IsInt32() {
return iso.ThrowException("Function CreateObject expects 2 Int32 parameters")
}
read := args[0].Int32()
written := args[1].Int32()
obj := v8go.NewObject(info.Context()) // create object
obj.Set("read", read) // set some properties
obj.Set("written", written)
return obj.Value
}
}

func injectObjectTester(ctx *v8go.Context, funcName string, funcCb v8go.FunctionCallback) error {
if ctx == nil {
return errors.New("ctx is required")
}

iso, err := ctx.Isolate()
if err != nil {
return fmt.Errorf("ctx.Isolate: %v", err)
}

con, err := v8go.NewObjectTemplate(iso)
if err != nil {
return fmt.Errorf("NewObjectTemplate: %v", err)
}

funcTempl, err := v8go.NewFunctionTemplate(iso, funcCb)
if err != nil {
return fmt.Errorf("NewFunctionTemplate: %v", err)
}

if err := con.Set(funcName, funcTempl, v8go.ReadOnly); err != nil {
return fmt.Errorf("ObjectTemplate.Set: %v", err)
}

nativeObj, err := con.NewInstance(ctx)
if err != nil {
return fmt.Errorf("ObjectTemplate.NewInstance: %v", err)
}

global := ctx.Global()

if err := global.Set("native", nativeObj); err != nil {
return fmt.Errorf("global.Set: %v", err)
}

return nil
}

// Test that golang can create an object with "read", "written" int32 properties and pass that back to JS.
func TestObjectCreate(t *testing.T) {
t.Parallel()
iso, _ := v8go.NewIsolate()
ctx, _ := v8go.NewContext(iso)
c := &objectTester{}

if err := injectObjectTester(ctx, "createObject", c.GetCreateObjectFunctionCallback()); err != nil {
t.Error(err)
}

js := `
obj = native.createObject(123, 456);
obj.read + obj.written;
`

val, err := ctx.RunScript(js, "")
if err != nil {
t.Errorf("Got error from script: %v", err)
}
if val == nil {
t.Errorf("Got nil value from script")
}
if !val.IsInt32() {
t.Errorf("Expected int32 value from script")
}
fmt.Printf("Script return value: %d\n", val.Int32())
if val.Int32() != 123+456 {
t.Errorf("Got wrong return value from script: %d", val.Int32())
}
}
13 changes: 13 additions & 0 deletions v8go.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,19 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr) {
LOCAL_VALUE(ptr) \
Local<Object> obj = value.As<Object>()

ValuePtr NewObject(IsolatePtr iso_ptr) {
ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr);
Local<Context> c = ctx->ptr.Get(iso);
Local<Object> obj = Object::New(iso);

m_value* val = new m_value;
val->iso = iso;
val->ctx = ctx;
val->ptr = Persistent<Value, CopyablePersistentTraits<Value>>(iso, obj);

return tracked_value(ctx, val);
}

void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr) {
LOCAL_OBJECT(ptr);
Local<String> key_val =
Expand Down
1 change: 1 addition & 0 deletions v8go.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ int ValueIsProxy(ValuePtr ptr);
int ValueIsWasmModuleObject(ValuePtr ptr);
int ValueIsModuleNamespaceObject(ValuePtr ptr);

extern ValuePtr NewObject(IsolatePtr iso_ptr);
extern void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr);
extern void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr);
extern RtnValue ObjectGet(ValuePtr ptr, const char* key);
Expand Down

0 comments on commit 88d85ab

Please sign in to comment.