2

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.

Johannes Ewald
  • 17,665
  • 5
  • 44
  • 39
  • I believe [issue 2088](https://github.com/rustwasm/wasm-bindgen/issues/2088) is relevant. Unfortunately, the issue seems pretty inactive, so the prettiest method right now is probably to just return a `JsValue`. – Aplet123 Mar 28 '21 at 15:11
  • Yes, enums would be great. When returning `JsValue` I would have to create the `Uint8Array`/`Unit16Array` manually, right? Btw: I went with solution 2 now since it's way less error prone despite being more code duplicated. – Johannes Ewald Apr 10 '21 at 00:23

0 Answers0