diff --git a/object.go b/object.go index 4c1dc5c59..9effa97fb 100644 --- a/object.go +++ b/object.go @@ -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) diff --git a/object_test.go b/object_test.go index 875d783b3..c899ab388 100644 --- a/object_test.go +++ b/object_test.go @@ -5,7 +5,9 @@ package v8go_test import ( + "errors" "fmt" + "log" "testing" "rogchap.com/v8go" @@ -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()) + } +} diff --git a/v8go.cc b/v8go.cc index 632675b63..4e4667886 100644 --- a/v8go.cc +++ b/v8go.cc @@ -1024,6 +1024,19 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr) { LOCAL_VALUE(ptr) \ Local obj = value.As() +ValuePtr NewObject(IsolatePtr iso_ptr) { + ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr); + Local c = ctx->ptr.Get(iso); + Local obj = Object::New(iso); + + m_value* val = new m_value; + val->iso = iso; + val->ctx = ctx; + val->ptr = Persistent>(iso, obj); + + return tracked_value(ctx, val); +} + void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr) { LOCAL_OBJECT(ptr); Local key_val = diff --git a/v8go.h b/v8go.h index d05b74b75..4f5dd0dd9 100644 --- a/v8go.h +++ b/v8go.h @@ -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);