-
Notifications
You must be signed in to change notification settings - Fork 18k
syscall/js: request: want to convert slices from/to TypedArray directly #32402
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
Comments
A possible workaround, for now, is to cast slices with |
@dennwc Thanks. Now I've succeeded to do what I wanted: func sliceToByteSlice(s interface{}) []byte {
switch s := s.(type) {
case []int8:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
return *(*[]byte)(unsafe.Pointer(h))
case []int16:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 2
h.Cap *= 2
return *(*[]byte)(unsafe.Pointer(h))
case []int32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
return *(*[]byte)(unsafe.Pointer(h))
case []int64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
return *(*[]byte)(unsafe.Pointer(h))
case []uint8:
return s
case []uint16:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 2
h.Cap *= 2
return *(*[]byte)(unsafe.Pointer(h))
case []uint32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
return *(*[]byte)(unsafe.Pointer(h))
case []uint64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
return *(*[]byte)(unsafe.Pointer(h))
case []float32:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 4
h.Cap *= 4
return *(*[]byte)(unsafe.Pointer(h))
case []float64:
h := (*reflect.SliceHeader)(unsafe.Pointer(&s))
h.Len *= 8
h.Cap *= 8
return *(*[]byte)(unsafe.Pointer(h))
default:
panic(fmt.Sprintf("jsutil: unexpected value at sliceToBytesSlice: %T", s))
}
}
func SliceToTypedArray(s interface{}) js.Value {
switch s := s.(type) {
case []int8:
a := js.Global().Get("Uint8Array").New(len(s))
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Int8Array").New(buf, a.Get("byteOffset"), a.Get("byteLength"))
case []int16:
a := js.Global().Get("Uint8Array").New(len(s) * 2)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Int16Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/2)
case []int32:
a := js.Global().Get("Uint8Array").New(len(s) * 4)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Int32Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/4)
case []uint8:
a := js.Global().Get("Uint8Array").New(len(s))
js.CopyBytesToJS(a, s)
runtime.KeepAlive(s)
return a
case []uint16:
a := js.Global().Get("Uint8Array").New(len(s) * 2)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Uint16Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/2)
case []uint32:
a := js.Global().Get("Uint8Array").New(len(s) * 4)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Uint32Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/4)
case []float32:
a := js.Global().Get("Uint8Array").New(len(s) * 4)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Float32Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/4)
case []float64:
a := js.Global().Get("Uint8Array").New(len(s) * 8)
js.CopyBytesToJS(a, sliceToByteSlice(s))
runtime.KeepAlive(s)
buf := a.Get("buffer")
return js.Global().Get("Float64Array").New(buf, a.Get("byteOffset"), a.Get("byteLength").Int()/8)
default:
panic(fmt.Sprintf("jsutil: unexpected value at SliceToTypedArray: %T", s))
}
} |
@hajimehoshi Is this available as a library somewhere? |
No so far. Ebiten has an internal package though: https://github.com/hajimehoshi/ebiten/tree/master/internal/jsutil |
Directly copied @hajimehoshi's workaround code from: golang/go#32402 (comment) No idea if it'll work with TinyGo wasm yet, as it uses reflect.
Using information found in comment in golang/go#32402
I resorted to patching
These methods get called quite often in my WebGL game and I can't afford indirection or extra syscalls used here: Looking for something similar to be included in the standard syscall/js library (supporting all other typed arrays too, not just Float32 which I am currently restricting myself to). An API like |
Using information found in comment in golang/go#32402
@finnbear For performance critical code you probably want to reuse a single buffer anyways. So first create a |
@hajimehoshi @finnbear Are you both happy with what is already possible? Shall we close this issue? |
@neelance I'm fine with CopyBytesToJS as-is, mostly because the option to use multiple typed arrays referencing the same buffer is available. I highly suggest you document that, although I'm still using the hack I showed above because my application commonly copies float32s and bytes. I'm fine with this issue being closed 👍 |
I'm fine with closing this issue. |
* where TypedArrayOf was removed & replaced with other techniques * the conversion was inspired & copied from issue golang/go#32402
* where TypedArrayOf was removed & replaced with other techniques * the conversion was inspired & copied from issue golang/go#32402
As
TypedArray
no longer exists as of Go 1.13, there is no way to convert slices other than[]byte
from/to TypedArray objects other thanUint8Array
. It is technically possible to do this by usingencoding/binary
, but I'm worried this conversion is not efficient.As there are Web APIs that take such TypedArray objects (e.g.,
AudioBuffer.copyToChannel
takes aFloat32Array
[1]), it would be very useful ifsyscall/js
had such conversion functions.CC @neelance
[1] https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer/copyToChannel
The text was updated successfully, but these errors were encountered: