Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add String type, constructor functions for it and Value.AsString to cast to it #277

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Add String type, constructor functions for it and Value.AsString() to cast to it

### Fixed
- Use string length to ensure null character-containing strings in Go/JS are not terminated early.
- Object.Set with an empty key string is now supported
Expand Down
4 changes: 1 addition & 3 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ func TestRegistryFromJSON(t *testing.T) {

global := v8.NewObjectTemplate(iso)
err := global.Set("location", v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {
v, err := v8.NewValue(iso, "world")
fatalIf(t, err)
return v
return v8.MustNewString(iso, "world").Value
}))
fatalIf(t, err)

Expand Down
2 changes: 1 addition & 1 deletion function_template_fetch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func ExampleFunctionTemplate_fetch() {
go func() {
res, _ := http.Get(url)
body, _ := ioutil.ReadAll(res.Body)
val, _ := v8.NewValue(iso, string(body))
val := v8.MustNewString(iso, string(body))
resolver.Resolve(val)
}()
return resolver.GetPromise().Value
Expand Down
4 changes: 2 additions & 2 deletions function_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func TestFunctionTemplateGetFunction(t *testing.T) {
var args *v8.FunctionCallbackInfo
tmpl := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {
args = info
reply, _ := v8.NewValue(iso, "hello")
return reply
reply := v8.MustNewString(iso, "hello")
return reply.Value
})
fn := tmpl.GetFunction(ctx)
ten, err := v8.NewValue(iso, int32(10))
Expand Down
3 changes: 1 addition & 2 deletions function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ func TestFunctionNewInstance(t *testing.T) {
fatalIf(t, err)
fn, err := value.AsFunction()
fatalIf(t, err)
messageObj, err := v8.NewValue(iso, "test message")
fatalIf(t, err)
messageObj := v8.MustNewString(iso, "test message")
errObj, err := fn.NewInstance(messageObj)
fatalIf(t, err)

Expand Down
2 changes: 1 addition & 1 deletion isolate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func TestIsolateThrowException(t *testing.T) {
t.Parallel()
iso := v8.NewIsolate()

strErr, _ := v8.NewValue(iso, "some type error")
strErr := v8.MustNewString(iso, "some type error").Value

throwError := func(val *v8.Value) {
v := iso.ThrowException(val)
Expand Down
2 changes: 1 addition & 1 deletion object_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestObjectTemplate(t *testing.T) {
}
}

val, _ := v8.NewValue(iso, "bar")
val := v8.MustNewString(iso, "bar").Value
objVal := v8.NewObjectTemplate(iso)
bigbigint, _ := new(big.Int).SetString("36893488147419099136", 10) // larger than a single word size (64bit)
bigbignegint, _ := new(big.Int).SetString("-36893488147419099136", 10)
Expand Down
2 changes: 1 addition & 1 deletion object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestObjectMethodCall(t *testing.T) {
val, err = ctx.RunScript(`class Obj2 { print(str) { return str.toString() }; get fails() { throw "error" } }; new Obj2()`, "")
fatalIf(t, err)
obj, _ = val.AsObject()
arg, _ := v8.NewValue(iso, "arg")
arg := v8.MustNewString(iso, "arg")
val, err = obj.MethodCall("print", arg)
fatalIf(t, err)
if val.String() != "arg" {
Expand Down
6 changes: 3 additions & 3 deletions promise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestPromiseFulfilled(t *testing.T) {
t.Error("unexpected call of Then prior to resolving the promise")
}

val1, _ := v8.NewValue(iso, "foo")
val1 := v8.MustNewString(iso, "foo")
res1.Resolve(val1)

if s := prom1.State(); s != v8.Fulfilled {
Expand Down Expand Up @@ -69,8 +69,8 @@ func TestPromiseRejected(t *testing.T) {
defer ctx.Close()

res2, _ := v8.NewPromiseResolver(ctx)
val2, _ := v8.NewValue(iso, "Bad Foo")
res2.Reject(val2)
val2 := v8.MustNewString(iso, "Bad Foo")
res2.Reject(val2.Value)

prom2 := res2.GetPromise()
if s := prom2.State(); s != v8.Rejected {
Expand Down
45 changes: 45 additions & 0 deletions string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2022 the v8go contributors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package v8go

// #include <stdlib.h>
// #include "v8go.h"
import "C"
import (
"unsafe"
)

// String is a JavaScript string object (ECMA-262, 4.3.17)
type String struct {
*Value
}

func jsStringResult(ctx *Context, rtn C.RtnValue) (String, error) {
if rtn.value == nil {
return String{nil}, newJSError(rtn.error)
}
return String{&Value{rtn.value, ctx}}, nil
}

// NewString returns a JS string from the Go string or an error if the string is longer than the max V8 string length.
func NewString(iso *Isolate, val string) (String, error) {
cstr := C.CString(val)
defer C.free(unsafe.Pointer(cstr))
rtn := C.NewValueString(iso.ptr, cstr, C.int(len(val)))
return jsStringResult(nil, rtn)
}

// MustNewString wraps NewString with a panic on error check.
//
// Use for strings known to be within than the max V8 string length.
// V8's max string length is (1 << 28) - 16 on 32-bit systems
// and (1 << 29) - 24 on other systems, at the time of writing.
func MustNewString(iso *Isolate, val string) String {
jsStr, err := NewString(iso, val)
if err != nil {
panic(err)
}
return jsStr
}
13 changes: 9 additions & 4 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,8 @@ func NewValue(iso *Isolate, val interface{}) (*Value, error) {

switch v := val.(type) {
case string:
cstr := C.CString(v)
defer C.free(unsafe.Pointer(cstr))
rtn := C.NewValueString(iso.ptr, cstr, C.int(len(v)))
return valueResult(nil, rtn)
str, err := NewString(iso, v)
return str.Value, err
case int32:
rtnVal = &Value{
ptr: C.NewValueInteger(iso.ptr, C.int(v)),
Expand Down Expand Up @@ -567,6 +565,13 @@ func (v *Value) AsFunction() (*Function, error) {
return &Function{v}, nil
}

func (v *Value) AsString() (*String, error) {
if !v.IsFunction() {
return nil, errors.New("v8go: value is not a String")
}
return &String{v}, nil
}

// MarshalJSON implements the json.Marshaler interface.
func (v *Value) MarshalJSON() ([]byte, error) {
jsonStr, err := JSONStringify(nil, v)
Expand Down