diff options
Diffstat (limited to 'src/syscall/js/js.go')
-rw-r--r-- | src/syscall/js/js.go | 106 |
1 files changed, 66 insertions, 40 deletions
diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go index 93c3965246..8217c24c5e 100644 --- a/src/syscall/js/js.go +++ b/src/syscall/js/js.go @@ -15,8 +15,14 @@ import ( "unsafe" ) -// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly itself. -type ref uint32 +// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly. +// A JavaScript number (64-bit float, except NaN) is represented by its IEEE 754 binary representation. +// All other values are represented as an IEEE 754 binary representation of NaN with the low 32 bits +// used as an ID. +type ref uint64 + +// nanHead are the upper 32 bits of a ref if the value is not a JavaScript number or NaN itself. +const nanHead = 0x7FF80000 // Value represents a JavaScript value. type Value struct { @@ -27,6 +33,17 @@ func makeValue(v ref) Value { return Value{ref: v} } +func predefValue(id uint32) Value { + return Value{ref: nanHead<<32 | ref(id)} +} + +func floatValue(f float64) Value { + if f != f { + return valueNaN + } + return Value{ref: *(*ref)(unsafe.Pointer(&f))} +} + // Error wraps a JavaScript error. type Error struct { // Value is the underlying JavaScript error value. @@ -39,11 +56,14 @@ func (e Error) Error() string { } var ( - valueUndefined = makeValue(0) - valueNull = makeValue(1) - valueGlobal = makeValue(2) - memory = makeValue(3) // WebAssembly linear memory - resolveCallbackPromise = makeValue(4) // function that the callback helper uses to resume the execution of Go's WebAssembly code + valueNaN = predefValue(0) + valueUndefined = predefValue(1) + valueNull = predefValue(2) + valueTrue = predefValue(3) + valueFalse = predefValue(4) + valueGlobal = predefValue(5) + memory = predefValue(6) // WebAssembly linear memory + resolveCallbackPromise = predefValue(7) // function that the callback helper uses to resume the execution of Go's WebAssembly code ) // Undefined returns the JavaScript value "undefined". @@ -73,35 +93,39 @@ func ValueOf(x interface{}) Value { case nil: return valueNull case bool: - return makeValue(boolVal(x)) + if x { + return valueTrue + } else { + return valueFalse + } case int: - return makeValue(intVal(x)) + return floatValue(float64(x)) case int8: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case int16: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case int32: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case int64: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uint: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uint8: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uint16: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uint32: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uint64: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case uintptr: - return makeValue(intVal(int(x))) + return floatValue(float64(x)) case unsafe.Pointer: - return makeValue(intVal(int(uintptr(x)))) + return floatValue(float64(uintptr(x))) case float32: - return makeValue(floatVal(float64(x))) + return floatValue(float64(x)) case float64: - return makeValue(floatVal(x)) + return floatValue(x) case string: return makeValue(stringVal(x)) case []byte: @@ -114,12 +138,6 @@ func ValueOf(x interface{}) Value { } } -func boolVal(x bool) ref - -func intVal(x int) ref - -func floatVal(x float64) ref - func stringVal(x string) ref // Get returns the JavaScript property p of value v. @@ -201,27 +219,35 @@ func (v Value) New(args ...interface{}) Value { func valueNew(v ref, args []ref) (ref, bool) -// Float returns the value v converted to float64 according to JavaScript type conversions (parseFloat). -func (v Value) Float() float64 { - return valueFloat(v.ref) +func (v Value) isNumber() bool { + return v.ref>>32 != nanHead || v.ref == valueNaN.ref } -func valueFloat(v ref) float64 +// Float returns the value v as a float64. It panics if v is not a JavaScript number. +func (v Value) Float() float64 { + if !v.isNumber() { + panic("syscall/js: not a number") + } + return *(*float64)(unsafe.Pointer(&v.ref)) +} -// Int returns the value v converted to int according to JavaScript type conversions (parseInt). +// Int returns the value v truncated to an int. It panics if v is not a JavaScript number. func (v Value) Int() int { - return valueInt(v.ref) + return int(v.Float()) } -func valueInt(v ref) int - -// Bool returns the value v converted to bool according to JavaScript type conversions. +// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean. func (v Value) Bool() bool { - return valueBool(v.ref) + switch v.ref { + case valueTrue.ref: + return true + case valueFalse.ref: + return false + default: + panic("syscall/js: not a boolean") + } } -func valueBool(v ref) bool - // String returns the value v converted to string according to JavaScript type conversions. func (v Value) String() string { str, length := valuePrepareString(v.ref) |