forked from rogchap/v8go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support creating a global ObjectTemplate into a context (rogchap#64)
* Support global Object Template into a context * add all supported primitive values to Object Template * add some examples to Context and document new API * don't convert to long types * add finalizer to new values created * update API for ObjectTemplate Set and other minor fixes
- Loading branch information
Showing
9 changed files
with
542 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package v8go | ||
|
||
// #include <stdlib.h> | ||
// #include "v8go.h" | ||
import "C" | ||
import ( | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
"runtime" | ||
"unsafe" | ||
) | ||
|
||
// PropertyAttribute are the attribute flags for a property on an Object. | ||
// Typical usage when setting an Object or TemplateObject property, and | ||
// can also be validated when accessing a property. | ||
type PropertyAttribute uint8 | ||
|
||
const ( | ||
// None. | ||
None PropertyAttribute = 0 | ||
// ReadOnly, ie. not writable. | ||
ReadOnly PropertyAttribute = 1 << iota | ||
// DontEnum, ie. not enumerable. | ||
DontEnum | ||
// DontDelete, ie. not configurable. | ||
DontDelete | ||
) | ||
|
||
// ObjectTemplate is used to create objects at runtime. | ||
// Properties added to an ObjectTemplate are added to each object created from the ObjectTemplate. | ||
type ObjectTemplate struct { | ||
ptr C.ObjectTemplatePtr | ||
iso *Isolate | ||
} | ||
|
||
// NewObjectTemplate creates a new ObjectTemplate. | ||
// The *ObjectTemplate can be used as a v8go.ContextOption to create a global object in a Context. | ||
func NewObjectTemplate(iso *Isolate) (*ObjectTemplate, error) { | ||
if iso == nil { | ||
return nil, errors.New("v8go: failed to create new ObjectTemplate: Isolate cannot be <nil>") | ||
} | ||
ob := &ObjectTemplate{ | ||
ptr: C.NewObjectTemplate(iso.ptr), | ||
iso: iso, | ||
} | ||
runtime.SetFinalizer(ob, (*ObjectTemplate).finalizer) | ||
return ob, nil | ||
} | ||
|
||
// Set adds a property to each instance created by this template. | ||
// The property must be defined either as a primitive value, or a template. | ||
// If the value passed is a Go supported primitive (string, int32, uint32, int64, uint64, float64, big.Int) | ||
// then a value will be created and set as the value property. | ||
func (o *ObjectTemplate) Set(name string, val interface{}, attributes ...PropertyAttribute) error { | ||
cname := C.CString(name) | ||
defer C.free(unsafe.Pointer(cname)) | ||
|
||
var attrs PropertyAttribute | ||
for _, a := range attributes { | ||
attrs |= a | ||
} | ||
|
||
switch v := val.(type) { | ||
case string, int32, uint32, int64, uint64, float64, bool, *big.Int: | ||
newVal, err := NewValue(o.iso, v) | ||
if err != nil { | ||
return fmt.Errorf("v8go: unable to create new value: %v", err) | ||
} | ||
C.ObjectTemplateSetValue(o.ptr, cname, newVal.ptr, C.int(attrs)) | ||
case *ObjectTemplate: | ||
C.ObjectTemplateSetObjectTemplate(o.ptr, cname, v.ptr, C.int(attrs)) | ||
case *Value: | ||
if v.IsObject() || v.IsExternal() { | ||
return errors.New("v8go: unsupported property: value type must be a primitive or use a template") | ||
} | ||
C.ObjectTemplateSetValue(o.ptr, cname, v.ptr, C.int(attrs)) | ||
default: | ||
return fmt.Errorf("v8go: unsupported property type `%T`, must be one of string, int32, uint32, int64, uint64, float64, *big.Int, *v8go.Value or *v8go.ObjectTemplate", v) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (o *ObjectTemplate) apply(opts *contextOptions) { | ||
opts.gTmpl = o | ||
} | ||
|
||
func (o *ObjectTemplate) finalizer() { | ||
C.ObjectTemplateDispose(o.ptr) | ||
o.ptr = nil | ||
runtime.SetFinalizer(o, nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package v8go_test | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"rogchap.com/v8go" | ||
) | ||
|
||
func TestObjectTemplate(t *testing.T) { | ||
t.Parallel() | ||
_, err := v8go.NewObjectTemplate(nil) | ||
if err == nil { | ||
t.Fatal("expected error but got <nil>") | ||
} | ||
iso, _ := v8go.NewIsolate() | ||
obj, err := v8go.NewObjectTemplate(iso) | ||
if err != nil { | ||
t.Fatalf("unexpected error: %v", err) | ||
} | ||
|
||
setError := func(t *testing.T, err error) { | ||
if err != nil { | ||
t.Errorf("failed to set property: %v", err) | ||
} | ||
} | ||
|
||
val, _ := v8go.NewValue(iso, "bar") | ||
objVal, _ := v8go.NewObjectTemplate(iso) | ||
bigbigint, _ := new(big.Int).SetString("36893488147419099136", 10) // larger than a single word size (64bit) | ||
|
||
tests := [...]struct { | ||
name string | ||
value interface{} | ||
}{ | ||
{"str", "foo"}, | ||
{"i32", int32(1)}, | ||
{"u32", uint32(1)}, | ||
{"i64", int64(1)}, | ||
{"u64", uint64(1)}, | ||
{"float64", float64(1)}, | ||
{"bigint", big.NewInt(1)}, | ||
{"bigbigint", bigbigint}, | ||
{"bool", true}, | ||
{"val", val}, | ||
{"obj", objVal}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tt := tt | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
setError(t, obj.Set(tt.name, tt.value, 0)) | ||
}) | ||
} | ||
} | ||
|
||
func TestGlobalObjectTemplate(t *testing.T) { | ||
t.Parallel() | ||
iso, _ := v8go.NewIsolate() | ||
tests := [...]struct { | ||
global func() *v8go.ObjectTemplate | ||
source string | ||
validate func(t *testing.T, val *v8go.Value) | ||
}{ | ||
{ | ||
func() *v8go.ObjectTemplate { | ||
gbl, _ := v8go.NewObjectTemplate(iso) | ||
gbl.Set("foo", "bar") | ||
return gbl | ||
}, | ||
"foo", | ||
func(t *testing.T, val *v8go.Value) { | ||
if !val.IsString() { | ||
t.Errorf("expect value %q to be of type String", val) | ||
return | ||
} | ||
if val.String() != "bar" { | ||
t.Errorf("unexpected value: %v", val) | ||
} | ||
}, | ||
}, | ||
{ | ||
func() *v8go.ObjectTemplate { | ||
foo, _ := v8go.NewObjectTemplate(iso) | ||
foo.Set("bar", "baz") | ||
gbl, _ := v8go.NewObjectTemplate(iso) | ||
gbl.Set("foo", foo) | ||
return gbl | ||
}, | ||
"foo.bar", | ||
func(t *testing.T, val *v8go.Value) { | ||
if val.String() != "baz" { | ||
t.Errorf("unexpected value: %v", val) | ||
} | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tt := tt | ||
t.Run(tt.source, func(t *testing.T) { | ||
t.Parallel() | ||
ctx, _ := v8go.NewContext(iso, tt.global()) | ||
val, err := ctx.RunScript(tt.source, "test.js") | ||
if err != nil { | ||
t.Fatalf("unexpected error runing script: %v", err) | ||
} | ||
tt.validate(t, val) | ||
}) | ||
} | ||
} |
Oops, something went wrong.