I want to expose a Rust library function to JavaScript that may return &[u8]
or &[u16]
depending on some condition. What's the most robust and performant way to do that?
I've come up with two possible solutions:
Solution 1: Just returning a Uint8Array
With this approach, I transmute &[u16]
to &[u8]
and then turn it into a Uint16Array
on the JS side:
#[wasm_bindgen]
pub fn my_function() -> Uint8Array {
// Pseudo-code
match some_condition {
IsU8 => rust_lib_function().into(),
IsU16 => {
unsafe { Uint8Array::view(&rust_lib_function().align_to().1) }
}
}
}
Afaik I need to be aware of endianess since JS TypedArrays
are platform endian. That's why I'm using dataView.getUint16
with littleEndian
explicitly set to true (because WebAssembly is using Little Endian, correct?).
const uint8Array = my_function();
const dataView = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
const length = uint8Array.byteLength / Uint16Array.BYTES_PER_ELEMENT;
const uint16Array = new Uint16Array(length);
for (let i = 0; i < length; i++) {
uint16Array[i] = dataView.getUint16(i * Uint16Array.BYTES_PER_ELEMENT, true /* littleEndian */);
}
Solution 2: Providing two separate functions
I could also provide two separate versions for my_function
that I could call depending on some condition. This would require the JS side to check the condition first.
#[wasm_bindgen]
pub fn my_function_u8() -> Uint8Array {
match some_condition {
IsU8 => rust_lib_function().into(),
IsU16 => {
panic!("Call my_function_u16");
}
}
}
#[wasm_bindgen]
pub fn my_function_u16() -> Uint16Array {
match some_condition {
IsU16 => rust_lib_function().into(),
IsU8 => {
panic!("Call my_function_u8");
}
}
}
Is there a simpler/more performant solution than the provided ones? Personally I prefer solution 1 since it's easier to maintain in the long term but I don't know if there are any issues with this approach. Since this function is going to be called very often I want to do as less copying as possible.