Types of Parameters
These are all the types of parameters that can be sent over the JS-Rust bridge:
ZapParam::String | |
Most common for small JSON-serialized data (e.g. using Serde). | |
Create in JS | "Hello, world!" |
Type in Rust | String |
Returned to JS | String |
Borrowing data | as_str() -> &str |
Transferring ownership | into_string() -> String |
Caveats | Data is copied when passed over the bridge. |
ZapParam::ReadOnlyU8Buffer | |
Most common for large serialized data. | |
Create in JS | zaplib.createReadOnlyBuffer(new Uint8Array([1, 2, 3])) |
Type in Rust | Arc<Vec<u8>> |
Returned to JS | ZapTypedArray (extends Uint8Array) |
Borrowing data | as_u8_slice() -> &[u8] |
Adding ownership (refcount) | as_arc_vec_u8() -> Arc<Vec<u8>> |
Caveats | No enforcement of read-only on JS side (yet). |
ZapParam::ReadOnlyF32Buffer | |
Most common for graphics data. | |
Same as above, but instead with f32 and Float32Array . | |
ZapParam::MutableU8Buffer | |
Less common. | |
Create in JS | zaplib.createMutableBuffer(new Uint8Array([1, 2, 3])) |
Type in Rust | Vec<u8> |
Returned to JS | ZapTypedArray (extends Uint8Array) |
Borrowing data | as_u8_slice() -> &[u8] |
Transferring ownership | into_vec_u8() -> Vec<u8> |
Caveats | Once passed from JS to Rust, the data cannot be used on the JS side any more (neither reading nor writing); representing transfer of ownership to Rust. This is not enforced (yet). |
ZapParam::MutableF32Buffer | |
Less common. | |
Same as above, but instead with f32 and Float32Array . |
As noted in the caveats above, you must take care when using these buffers on the JavaScript side:
- Read-only buffers should not be mutated in JS. If you do mutate them anyway, race conditions and data corruption can occur. This restriction is not enforced (yet).
- Mutable buffers can be mutated in JS. However, once you pass a mutable buffer into Rust, you cannot use the buffer in JS in any way. This is because ownership is passed to Rust, which can now mutate the data. If you read from such a stale buffer in JS, race conditions and data corruption can occur. This restriction is not enforced (yet).
- It is possible to mutate some data in JS, then in Rust, and then in JS again, without ever copying of the data. Just pass the mutable buffer back from Rust to JS when you're done with it.
When a u8
or f32
buffer is returned to JS, you get a ZapTypedArray
:
- This extends either
Uint8Array
orFloat32Array
. - This typed array is backed by the WebAssembly memory.
- When the typed array gets garbage collected, the WebAssembly memory is updated accordingly (the refcount is decreased for read-only buffers; and the memory is freed for mutable buffers).
- This does mean that if you want to pass such a typed array to a Web Worker, that you have to use
zaplib.serializeZapArrayForPostMessage
. If you don't, the data might get de- or re-allocated before you can use it.- This is enforced by monkey-patching
postMessage
when you callzaplib.initialize()
, so don't worry too much about it.
- This is enforced by monkey-patching
- It is possible to call
subarray()
on these typed arrays, and the garbage collection be tracked properly.- It is even possible to create a new typed array using
new Uint8Array(zapArray.buffer, zapArray.byteOffset, zapArray.length)
, and the garbage collection will still be tracked properly! - This makes it possible to pass these typed arrays into most existing libraries.
- However, it's not possible to pass a sub-slice of a typed array to Rust.
- It is even possible to create a new typed array using
When sending small amounts of data in either direction, we recommend simply JSON-serializing the data and sending it as a string. On the Rust side, Serde is a fine library for this.
Futher note that when using Zapium, data is often copied anyway, even when in the WebAssembly version it is not. This is one of the reasons why we do not recommend using Zapium yet.