1 Star 0 Fork 0

似是故人来/v8go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
value.go 18.14 KB
一键复制 编辑 原始数据 按行查看 历史
zhengkaikai 提交于 2023-05-25 12:14 . 更新 mac arm64
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
// Copyright 2019 Roger Chapman and 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 (
"errors"
"fmt"
"io"
"math/big"
"runtime"
"unsafe"
)
type valuer interface {
value() *Value
}
// Value represents all Javascript values and objects
type Value struct {
ptr C.ValuePtr
ISO *Isolate
}
func NewValueStruct(valPtr C.ValuePtr, c *Isolate) (ret *Value) {
defer func() {
runtime.SetFinalizer(ret, MarkValuePtrCanReleaseInC)
}()
if c != nil {
c.TraceValuePtr(valPtr)
}
if TraceMem {
fmt.Println("New Value")
}
v := &Value{
ptr: valPtr,
ISO: c,
}
return v
}
func (v *Value) MarkValuePtrCanReleaseInC() {
runtime.SetFinalizer(v, nil)
v.ISO.MoveTracedPtrToCanReleaseMap(v.ptr, true)
}
func MarkValuePtrCanReleaseInC(v *Value) {
v.MarkValuePtrCanReleaseInC()
}
func (v *Value) value() *Value {
return v
}
func newValueNull(iso *Isolate) *Value {
return NewValueStruct(C.NewValueNull(iso.ptr), iso)
}
func newValueUndefined(iso *Isolate) *Value {
return NewValueStruct(C.NewValueUndefined(iso.ptr), iso)
}
// Undefined returns the `undefined` JS value
func Undefined(iso *Isolate) *Value {
return iso.undefined
}
// Null returns the `null` JS value
func Null(iso *Isolate) *Value {
return iso.null
}
// NewValue will create a primitive value. Supported values types to create are:
// int -> V8::BigInt
// int8 -> V8::Integer
// int16 -> V8::Integer
// int32 -> V8::Integer
// int64 -> V8::BigInt
// uint -> V8::BigInt
// uint8 -> V8::Integer
// uint16 -> V8::Integer
// uint32 -> V8::Integer
// uint64 -> V8::BigInt
// string -> V8::String
// bool -> V8::Boolean
// bool -> V8::Boolean
// *big.Int -> V8::BigInt
func NewValue(iso *Isolate, val interface{}) (rtnVal *Value, e error) {
if iso == nil {
return nil, errors.New("v8go: failed to create new Value: Isolate cannot be <nil>")
}
switch v := val.(type) {
case string:
cstr := C.CString(v)
defer FreeCPtr(unsafe.Pointer(cstr))
rtn := C.NewValueString(iso.ptr, cstr)
return valueResult(iso, rtn)
case int8:
rtnVal = NewValueStruct(C.NewValueInteger(iso.ptr, C.int(int32(v))), iso)
case int16:
rtnVal = NewValueStruct(C.NewValueInteger(iso.ptr, C.int(int32(v))), iso)
case int32:
rtnVal = NewValueStruct(C.NewValueInteger(iso.ptr, C.int(v)), iso)
case uint8:
rtnVal = NewValueStruct(C.NewValueIntegerFromUnsigned(iso.ptr, C.uint(uint32(v))), iso)
case uint16:
rtnVal = NewValueStruct(C.NewValueIntegerFromUnsigned(iso.ptr, C.uint(uint32(v))), iso)
case uint32:
rtnVal = NewValueStruct(C.NewValueIntegerFromUnsigned(iso.ptr, C.uint(v)), iso)
case int:
rtnVal = NewValueStruct(C.NewValueBigInt(iso.ptr, C.int64_t(int64(v))), iso)
case uint:
rtnVal = NewValueStruct(C.NewValueBigIntFromUnsigned(iso.ptr, C.uint64_t(uint64(v))), iso)
case int64:
rtnVal = NewValueStruct(C.NewValueBigInt(iso.ptr, C.int64_t(v)), iso)
case uint64:
rtnVal = NewValueStruct(C.NewValueBigIntFromUnsigned(iso.ptr, C.uint64_t(v)), iso)
case bool:
var b int
if v {
b = 1
}
rtnVal = NewValueStruct(C.NewValueBoolean(iso.ptr, C.int(b)), iso)
case float32:
rtnVal = NewValueStruct(C.NewValueNumber(iso.ptr, C.double(float64(v))), iso)
case float64:
rtnVal = NewValueStruct(C.NewValueNumber(iso.ptr, C.double(v)), iso)
case *big.Int:
if v.IsInt64() {
rtnVal = NewValueStruct(C.NewValueBigInt(iso.ptr, C.int64_t(v.Int64())), iso)
break
}
if v.IsUint64() {
rtnVal = NewValueStruct(C.NewValueBigIntFromUnsigned(iso.ptr, C.uint64_t(v.Uint64())), iso)
break
}
var sign, count int
if v.Sign() == -1 {
sign = 1
}
bits := v.Bits()
count = len(bits)
words := make([]C.uint64_t, count, count)
for idx, word := range bits {
words[idx] = C.uint64_t(word)
}
rtn := C.NewValueBigIntFromWords(iso.ptr, C.int(sign), C.int(count), &words[0])
return valueResult(iso, rtn)
case []byte:
byteLen := len(v)
if byteLen == 0 {
rtnVal = Undefined(iso)
} else {
v8V := C.NewArrayBufferFromGoBytes(iso.ptr, unsafe.Pointer(&v[0]), C.size_t(byteLen))
rtnVal = NewValueStruct(v8V, iso)
}
default:
return nil, fmt.Errorf("v8go: unsupported value type `%T`", v)
}
return rtnVal, nil
}
// Format implements the fmt.Formatter interface to provide a custom formatter
// primarily to output the detail string (for debugging) with `%+v` verb.
func (v *Value) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, v.DetailString())
return
}
fallthrough
case 's':
io.WriteString(s, v.String())
case 'q':
fmt.Fprintf(s, "%q", v.String())
}
}
// ArrayIndex attempts to converts a string to an array index. Returns ok false if conversion fails.
func (v *Value) ArrayIndex() (idx uint32, ok bool) {
arrayIdx := C.ValueToArrayIndex(v.ptr)
defer FreeCPtr(unsafe.Pointer(arrayIdx))
if arrayIdx == nil {
return 0, false
}
return uint32(*arrayIdx), true
}
// BigInt perform the equivalent of `BigInt(value)` in JS.
func (v *Value) BigInt() *big.Int {
if v == nil {
return nil
}
bint := C.ValueToBigInt(v.ptr)
defer FreeCPtr(unsafe.Pointer(bint.word_array))
if bint.word_array == nil {
return nil
}
words := (*[1 << 30]big.Word)(unsafe.Pointer(bint.word_array))[:bint.word_count:bint.word_count]
abs := make([]big.Word, len(words))
copy(abs, words)
b := &big.Int{}
b.SetBits(abs)
if bint.sign_bit == 1 {
b.Neg(b)
}
return b
}
// Boolean perform the equivalent of `Boolean(value)` in JS. This can never fail.
func (v *Value) Boolean() bool {
return C.ValueToBoolean(v.ptr) != 0
}
// DetailString provide a string representation of this value usable for debugging.
func (v *Value) DetailString() string {
rtn := C.ValueToDetailString(v.ptr)
if rtn.string == nil {
err := newJSError(rtn.error)
panic(err) // TODO: Return a fallback value
}
s := rtn.string
defer FreeCPtr(unsafe.Pointer(s))
return C.GoString(s)
}
// Int32 perform the equivalent of `Number(value)` in JS and convert the result to a
// signed 32-bit integer by performing the steps in https://tc39.es/ecma262/#sec-toint32.
func (v *Value) Int32() int32 {
return int32(C.ValueToInt32(v.ptr))
}
// Integer perform the equivalent of `Number(value)` in JS and convert the result to an integer.
// Negative values are rounded up, positive values are rounded down. NaN is converted to 0.
// Infinite values yield undefined results.
func (v *Value) Integer() int64 {
return int64(C.ValueToInteger(v.ptr))
}
// Number perform the equivalent of `Number(value)` in JS.
func (v *Value) Number() float64 {
return float64(C.ValueToNumber(v.ptr))
}
// Object perform the equivalent of Object(value) in JS.
// To just cast this value as an Object use AsObject() instead.
func (v *Value) Object() *Object {
rtn := C.ValueToObject(v.ptr)
obj, err := objectResult(v.ISO, rtn)
if err != nil {
panic(err) // TODO: Return error
}
return obj
}
// String perform the equivalent of `String(value)` in JS. Primitive values
// are returned as-is, objects will return `[object Object]` and functions will
// print their definition.
func (v *Value) String() string {
s := C.ValueToString(v.ptr)
gostring := C.GoString(s)
FreeModuleCPtr(unsafe.Pointer(s))
return gostring
}
// Uint32 perform the equivalent of `Number(value)` in JS and convert the result to an
// unsigned 32-bit integer by performing the steps in https://tc39.es/ecma262/#sec-touint32.
func (v *Value) Uint32() uint32 {
return uint32(C.ValueToUint32(v.ptr))
}
// SameValue returns true if the other value is the same value.
// This is equivalent to `Object.is(v, other)` in JS.
func (v *Value) SameValue(other *Value) bool {
return C.ValueSameValue(v.ptr, other.ptr) != 0
}
// IsUndefined returns true if this value is the undefined value. See ECMA-262 4.3.10.
func (v *Value) IsUndefined() bool {
return C.ValueIsUndefined(v.ptr) != 0
}
// IsNull returns true if this value is the null value. See ECMA-262 4.3.11.
func (v *Value) IsNull() bool {
return C.ValueIsNull(v.ptr) != 0
}
// IsNullOrUndefined returns true if this value is either the null or the undefined value.
// See ECMA-262 4.3.11. and 4.3.12
// This is equivalent to `value == null` in JS.
func (v *Value) IsNullOrUndefined() bool {
return C.ValueIsNullOrUndefined(v.ptr) != 0
}
// IsTrue returns true if this value is true.
// This is not the same as `BooleanValue()`. The latter performs a conversion to boolean,
// i.e. the result of `Boolean(value)` in JS, whereas this checks `value === true`.
func (v *Value) IsTrue() bool {
return C.ValueIsTrue(v.ptr) != 0
}
// IsFalse returns true if this value is false.
// This is not the same as `!BooleanValue()`. The latter performs a conversion to boolean,
// i.e. the result of `!Boolean(value)` in JS, whereas this checks `value === false`.
func (v *Value) IsFalse() bool {
return C.ValueIsFalse(v.ptr) != 0
}
// IsName returns true if this value is a symbol or a string.
// This is equivalent to `typeof value === 'string' || typeof value === 'symbol'` in JS.
func (v *Value) IsName() bool {
return C.ValueIsName(v.ptr) != 0
}
// IsString returns true if this value is an instance of the String type. See ECMA-262 8.4.
// This is equivalent to `typeof value === 'string'` in JS.
func (v *Value) IsString() bool {
return C.ValueIsString(v.ptr) != 0
}
// IsSymbol returns true if this value is a symbol.
// This is equivalent to `typeof value === 'symbol'` in JS.
func (v *Value) IsSymbol() bool {
return C.ValueIsSymbol(v.ptr) != 0
}
// IsFunction returns true if this value is a function.
// This is equivalent to `typeof value === 'function'` in JS.
func (v *Value) IsFunction() bool {
return C.ValueIsFunction(v.ptr) != 0
}
// IsObject returns true if this value is an object.
func (v *Value) IsObject() bool {
return v.ISO != nil && C.ValueIsObject(v.ptr) != 0
}
// IsBigInt returns true if this value is a bigint.
// This is equivalent to `typeof value === 'bigint'` in JS.
func (v *Value) IsBigInt() bool {
return C.ValueIsBigInt(v.ptr) != 0
}
// IsBoolean returns true if this value is boolean.
// This is equivalent to `typeof value === 'boolean'` in JS.
func (v *Value) IsBoolean() bool {
return C.ValueIsBoolean(v.ptr) != 0
}
// IsNumber returns true if this value is a number.
// This is equivalent to `typeof value === 'number'` in JS.
func (v *Value) IsNumber() bool {
return C.ValueIsNumber(v.ptr) != 0
}
// IsExternal returns true if this value is an `External` object.
func (v *Value) IsExternal() bool {
// TODO(rogchap): requires test case
return v.ISO != nil && C.ValueIsExternal(v.ptr) != 0
}
// IsInt32 returns true if this value is a 32-bit signed integer.
func (v *Value) IsInt32() bool {
return C.ValueIsInt32(v.ptr) != 0
}
// IsUint32 returns true if this value is a 32-bit unsigned integer.
func (v *Value) IsUint32() bool {
return C.ValueIsUint32(v.ptr) != 0
}
// IsDate returns true if this value is a `Date`.
func (v *Value) IsDate() bool {
return C.ValueIsDate(v.ptr) != 0
}
// IsArgumentsObject returns true if this value is an Arguments object.
func (v *Value) IsArgumentsObject() bool {
return C.ValueIsArgumentsObject(v.ptr) != 0
}
// IsBigIntObject returns true if this value is a BigInt object.
func (v *Value) IsBigIntObject() bool {
return C.ValueIsBigIntObject(v.ptr) != 0
}
// IsNumberObject returns true if this value is a `Number` object.
func (v *Value) IsNumberObject() bool {
return C.ValueIsNumberObject(v.ptr) != 0
}
// IsStringObject returns true if this value is a `String` object.
func (v *Value) IsStringObject() bool {
return C.ValueIsStringObject(v.ptr) != 0
}
// IsSymbolObject returns true if this value is a `Symbol` object.
func (v *Value) IsSymbolObject() bool {
return C.ValueIsSymbolObject(v.ptr) != 0
}
// IsNativeError returns true if this value is a NativeError.
func (v *Value) IsNativeError() bool {
return C.ValueIsNativeError(v.ptr) != 0
}
// IsRegExp returns true if this value is a `RegExp`.
func (v *Value) IsRegExp() bool {
return C.ValueIsRegExp(v.ptr) != 0
}
// IsAsyncFunc returns true if this value is an async function.
func (v *Value) IsAsyncFunction() bool {
return C.ValueIsAsyncFunction(v.ptr) != 0
}
// Is IsGeneratorFunc returns true if this value is a Generator function.
func (v *Value) IsGeneratorFunction() bool {
return C.ValueIsGeneratorFunction(v.ptr) != 0
}
// IsGeneratorObject returns true if this value is a Generator object (iterator).
func (v *Value) IsGeneratorObject() bool {
return C.ValueIsGeneratorObject(v.ptr) != 0
}
// IsPromise returns true if this value is a `Promise`.
func (v *Value) IsPromise() bool {
return C.ValueIsPromise(v.ptr) != 0
}
// IsMap returns true if this value is a `Map`.
func (v *Value) IsMap() bool {
return C.ValueIsMap(v.ptr) != 0
}
// IsSet returns true if this value is a `Set`.
func (v *Value) IsSet() bool {
return C.ValueIsSet(v.ptr) != 0
}
// IsMapIterator returns true if this value is a `Map` Iterator.
func (v *Value) IsMapIterator() bool {
return C.ValueIsMapIterator(v.ptr) != 0
}
// IsSetIterator returns true if this value is a `Set` Iterator.
func (v *Value) IsSetIterator() bool {
return C.ValueIsSetIterator(v.ptr) != 0
}
// IsWeakMap returns true if this value is a `WeakMap`.
func (v *Value) IsWeakMap() bool {
return C.ValueIsWeakMap(v.ptr) != 0
}
// IsWeakSet returns true if this value is a `WeakSet`.
func (v *Value) IsWeakSet() bool {
return C.ValueIsWeakSet(v.ptr) != 0
}
// IsArray returns true if this value is an array.
// Note that it will return false for a `Proxy` of an array.
func (v *Value) IsArray() bool {
return C.ValueIsArray(v.ptr) != 0
}
// IsArrayBuffer returns true if this value is an `ArrayBuffer`.
func (v *Value) IsArrayBuffer() bool {
return C.ValueIsArrayBuffer(v.ptr) != 0
}
// IsArrayBufferView returns true if this value is an `ArrayBufferView`.
func (v *Value) IsArrayBufferView() bool {
return C.ValueIsArrayBufferView(v.ptr) != 0
}
// IsTypedArray returns true if this value is one of TypedArrays.
func (v *Value) IsTypedArray() bool {
return C.ValueIsTypedArray(v.ptr) != 0
}
// IsUint8Array returns true if this value is an `Uint8Array`.
func (v *Value) IsUint8Array() bool {
return C.ValueIsUint8Array(v.ptr) != 0
}
// IsUint8ClampedArray returns true if this value is an `Uint8ClampedArray`.
func (v *Value) IsUint8ClampedArray() bool {
return C.ValueIsUint8ClampedArray(v.ptr) != 0
}
// IsInt8Array returns true if this value is an `Int8Array`.
func (v *Value) IsInt8Array() bool {
return C.ValueIsInt8Array(v.ptr) != 0
}
// IsUint16Array returns true if this value is an `Uint16Array`.
func (v *Value) IsUint16Array() bool {
return C.ValueIsUint16Array(v.ptr) != 0
}
// IsInt16Array returns true if this value is an `Int16Array`.
func (v *Value) IsInt16Array() bool {
return C.ValueIsInt16Array(v.ptr) != 0
}
// IsUint32Array returns true if this value is an `Uint32Array`.
func (v *Value) IsUint32Array() bool {
return C.ValueIsUint32Array(v.ptr) != 0
}
// IsInt32Array returns true if this value is an `Int32Array`.
func (v *Value) IsInt32Array() bool {
return C.ValueIsInt32Array(v.ptr) != 0
}
// IsFloat32Array returns true if this value is a `Float32Array`.
func (v *Value) IsFloat32Array() bool {
return C.ValueIsFloat32Array(v.ptr) != 0
}
// IsFloat64Array returns true if this value is a `Float64Array`.
func (v *Value) IsFloat64Array() bool {
return C.ValueIsFloat64Array(v.ptr) != 0
}
// IsBigInt64Array returns true if this value is a `BigInt64Array`.
func (v *Value) IsBigInt64Array() bool {
return C.ValueIsBigInt64Array(v.ptr) != 0
}
// IsBigUint64Array returns true if this value is a BigUint64Array`.
func (v *Value) IsBigUint64Array() bool {
return C.ValueIsBigUint64Array(v.ptr) != 0
}
// IsDataView returns true if this value is a `DataView`.
func (v *Value) IsDataView() bool {
return C.ValueIsDataView(v.ptr) != 0
}
// IsSharedArrayBuffer returns true if this value is a `SharedArrayBuffer`.
func (v *Value) IsSharedArrayBuffer() bool {
return C.ValueIsSharedArrayBuffer(v.ptr) != 0
}
// IsProxy returns true if this value is a JavaScript `Proxy`.
func (v *Value) IsProxy() bool {
return C.ValueIsProxy(v.ptr) != 0
}
// IsWasmModuleObject returns true if this value is a `WasmModuleObject`.
func (v *Value) IsWasmModuleObject() bool {
// TODO(rogchap): requires test case
return C.ValueIsWasmModuleObject(v.ptr) != 0
}
// IsModuleNamespaceObject returns true if the value is a `Module` Namespace `Object`.
func (v *Value) IsModuleNamespaceObject() bool {
// TODO(rogchap): requires test case
return C.ValueIsModuleNamespaceObject(v.ptr) != 0
}
// AsObject will cast the value to the Object type. If the value is not an Object
// then an error is returned. Use `value.Object()` to do the JS equivalent of `Object(value)`.
func (v *Value) AsObject() (*Object, error) {
if !v.IsObject() {
return nil, errors.New("v8go: value is not an Object")
}
return &Object{v}, nil
}
func (v *Value) AsPromise() (*Promise, error) {
if !v.IsPromise() {
return nil, errors.New("v8go: value is not a Promise")
}
return &Promise{&Object{v}}, nil
}
func (v *Value) AsFunction() (*Function, error) {
if !v.IsFunction() {
return nil, errors.New("v8go: value is not a Function")
}
return &Function{v}, nil
}
func (v *Value) AsObjectTemplate() *ObjectTemplate {
iso := v.ISO
tmpl := &template{
ptr: C.ObjectTemplateFromValue(v.ISO.ptr, v.ptr),
iso: iso,
}
iso.templateLock.Lock()
defer iso.templateLock.Unlock()
iso.templates = append(iso.templates, tmpl)
return &ObjectTemplate{tmpl}
}
// MarshalJSON implements the json.Marshaler interface.
func (v *Value) MarshalJSON() ([]byte, error) {
jsonStr, err := JSONStringify(nil, v)
if err != nil {
return nil, err
}
return []byte(jsonStr), nil
}
func (v *Value) GetCopiedArrayBufferViewContents() []byte {
bufferViewByteLen := C.GetArrayBufferViewByteLen(v.ptr)
if bufferViewByteLen == 0 {
return make([]byte, 0)
}
buffer := make([]byte, int(bufferViewByteLen))
copiedLen := int(C.CopyArrayBufferViewContent(v.ptr, unsafe.Pointer(&buffer[0])))
return buffer[0:copiedLen]
}
func (v *Value) GetCopiedArrayBufferContents() []byte {
bufferViewByteLen := C.GetArrayBufferByteLen(v.ptr)
if bufferViewByteLen == 0 {
return make([]byte, 0)
}
buffer := make([]byte, int(bufferViewByteLen))
copiedLen := int(C.CopyArrayBufferContent(v.ptr, unsafe.Pointer(&buffer[0])))
return buffer[0:copiedLen]
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/hasika/v8go.git
[email protected]:hasika/v8go.git
hasika
v8go
v8go
master

搜索帮助