-
-
Notifications
You must be signed in to change notification settings - Fork 221
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Function Templates with callback functions in Go (#68)
* refactor to extend from private template struct * refactor the C++ side to also match base class template * Basic callbacks with arguments * fix stat now there is an internal context * deal with Go -> C pointer madness * apply formatting and add examples * add tests to the function template and the registries * simplify, bug fixes and add comments
- Loading branch information
Showing
14 changed files
with
585 additions
and
161 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package v8go | ||
|
||
// RegisterCallback is exported for testing only. | ||
func (i *Isolate) RegisterCallback(cb FunctionCallback) int { | ||
return i.registerCallback(cb) | ||
} | ||
|
||
// GetCallback is exported for testing only. | ||
func (i *Isolate) GetCallback(ref int) FunctionCallback { | ||
return i.getCallback(ref) | ||
} | ||
|
||
// Register is exported for testing only. | ||
func (c *Context) Register() { | ||
c.register() | ||
} | ||
|
||
// Deregister is exported for testing only. | ||
func (c *Context) Deregister() { | ||
c.deregister() | ||
} | ||
|
||
// GetContext is exported for testing only. | ||
var GetContext = getContext | ||
|
||
// Ref is exported for testing only. | ||
func (c *Context) Ref() int { | ||
return c.ref | ||
} |
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,78 @@ | ||
package v8go | ||
|
||
// #include <stdlib.h> | ||
// #include "v8go.h" | ||
import "C" | ||
import ( | ||
"errors" | ||
"runtime" | ||
"unsafe" | ||
) | ||
|
||
// FunctionCallback is a callback that is executed in Go when a function is executed in JS. | ||
type FunctionCallback func(info *FunctionCallbackInfo) *Value | ||
|
||
// FunctionCallbackInfo is the argument that is passed to a FunctionCallback. | ||
type FunctionCallbackInfo struct { | ||
ctx *Context | ||
args []*Value | ||
} | ||
|
||
// Context is the current context that the callback is being executed in. | ||
func (i *FunctionCallbackInfo) Context() *Context { | ||
return i.ctx | ||
} | ||
|
||
// Args returns a slice of the value arguments that are passed to the JS function. | ||
func (i *FunctionCallbackInfo) Args() []*Value { | ||
return i.args | ||
} | ||
|
||
// FunctionTemplate is used to create functions at runtime. | ||
// There can only be one function created from a FunctionTemplate in a context. | ||
// The lifetime of the created function is equal to the lifetime of the context. | ||
type FunctionTemplate struct { | ||
*template | ||
} | ||
|
||
// NewFunctionTemplate creates a FunctionTemplate for a given callback. | ||
func NewFunctionTemplate(iso *Isolate, callback FunctionCallback) (*FunctionTemplate, error) { | ||
if iso == nil { | ||
return nil, errors.New("v8go: failed to create new FunctionTemplate: Isolate cannot be <nil>") | ||
} | ||
if callback == nil { | ||
return nil, errors.New("v8go: failed to create new FunctionTemplate: FunctionCallback cannot be <nil>") | ||
} | ||
|
||
cbref := iso.registerCallback(callback) | ||
|
||
tmpl := &template{ | ||
ptr: C.NewFunctionTemplate(iso.ptr, C.int(cbref)), | ||
iso: iso, | ||
} | ||
runtime.SetFinalizer(tmpl, (*template).finalizer) | ||
return &FunctionTemplate{tmpl}, nil | ||
} | ||
|
||
//export goFunctionCallback | ||
func goFunctionCallback(ctxref int, cbref int, args *C.ValuePtr, argsCount int) C.ValuePtr { | ||
ctx := getContext(ctxref) | ||
|
||
info := &FunctionCallbackInfo{ | ||
ctx: ctx, | ||
args: make([]*Value, argsCount), | ||
} | ||
|
||
argv := (*[1 << 30]C.ValuePtr)(unsafe.Pointer(args))[:argsCount:argsCount] | ||
for i, v := range argv { | ||
val := &Value{ptr: v} | ||
runtime.SetFinalizer(val, (*Value).finalizer) | ||
info.args[i] = val | ||
} | ||
|
||
callbackFunc := ctx.iso.getCallback(cbref) | ||
if val := callbackFunc(info); val != nil { | ||
return val.ptr | ||
} | ||
return 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,65 @@ | ||
package v8go_test | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"strings" | ||
"testing" | ||
|
||
"rogchap.com/v8go" | ||
) | ||
|
||
func TestFunctionTemplate(t *testing.T) { | ||
t.Parallel() | ||
|
||
if _, err := v8go.NewFunctionTemplate(nil, func(*v8go.FunctionCallbackInfo) *v8go.Value { return nil }); err == nil { | ||
t.Error("expected error but got <nil>") | ||
} | ||
|
||
iso, _ := v8go.NewIsolate() | ||
if _, err := v8go.NewFunctionTemplate(iso, nil); err == nil { | ||
t.Error("expected error but got <nil>") | ||
} | ||
|
||
fn, err := v8go.NewFunctionTemplate(iso, func(*v8go.FunctionCallbackInfo) *v8go.Value { return nil }) | ||
if err != nil { | ||
t.Errorf("unexpected error: %v", err) | ||
} | ||
if fn == nil { | ||
t.Error("expected FunctionTemplate, but got <nil>") | ||
} | ||
} | ||
|
||
func ExampleFunctionTemplate() { | ||
iso, _ := v8go.NewIsolate() | ||
global, _ := v8go.NewObjectTemplate(iso) | ||
printfn, _ := v8go.NewFunctionTemplate(iso, func(info *v8go.FunctionCallbackInfo) *v8go.Value { | ||
fmt.Printf("%+v\n", info.Args()) | ||
return nil | ||
}) | ||
global.Set("print", printfn, v8go.ReadOnly) | ||
ctx, _ := v8go.NewContext(iso, global) | ||
ctx.RunScript("print('foo', 'bar', 0, 1)", "") | ||
// Output: | ||
// [foo bar 0 1] | ||
} | ||
|
||
func ExampleFunctionTemplate_fetch() { | ||
iso, _ := v8go.NewIsolate() | ||
global, _ := v8go.NewObjectTemplate(iso) | ||
fetchfn, _ := v8go.NewFunctionTemplate(iso, func(info *v8go.FunctionCallbackInfo) *v8go.Value { | ||
args := info.Args() | ||
url := args[0].String() | ||
res, _ := http.Get(url) | ||
body, _ := ioutil.ReadAll(res.Body) | ||
val, _ := v8go.NewValue(iso, string(body)) | ||
return val | ||
}) | ||
global.Set("fetch", fetchfn, v8go.ReadOnly) | ||
ctx, _ := v8go.NewContext(iso, global) | ||
val, _ := ctx.RunScript("fetch('https://rogchap.com/v8go')", "") | ||
fmt.Printf("%s\n", strings.Split(val.String(), "\n")[0]) | ||
// Output: | ||
// <!DOCTYPE html> | ||
} |
Oops, something went wrong.