Search code examples
rustfrontendwebassemblywasm-bindgenwasm-pack

How to return a tuple to frontend from wasm?


I'm new to webassembly. I want to create a simple greedy snake game using canvas and wasm_bindgen.

My rust code:

#[wasm_bindgen]
impl CanvasData {
    pub fn index_to_coordinate(&self, index: usize) -> (usize, usize) {
      (index % self.cell_count, index / self.cell_count)
    }
}

CanvasData is a struct that saves data of the canvas, cell_count attribute is usize type, it represents the number of horizontal and vertical grids on the square canvas. Here I treat all the grids on the canvas as a one-dimensional array from left to right and from top to bottom. The purpose of this method is to map the array index to x, y coordinates. I want to return a tuple and call it in the front end as follows:

const [x, y] = canvasData.index_to_coordinate(100)

However, an error occurred during building.

Build script:

wasm-pack build -t web

Error:

error[E0277]: the trait bound `(usize, usize): IntoWasmAbi` is not satisfied
[0]   --> src\lib.rs:16:1
[0]    |
[0] 16 | #[wasm_bindgen]
[0]    | ^^^^^^^^^^^^^^^ the trait `IntoWasmAbi` is not implemented for `(usize, usize)`
[0]    |
[0]    = help: the trait `IntoWasmAbi` is implemented for `()`
[0]    = note: required because of the requirements on the impl of `ReturnWasmAbi` for `(usize, usize)`
[0]    = note: this error originates in the attribute macro `wasm_bindgen::prelude::__wasm_bindgen_class_marker` (in Nightly builds, run with -Z macro-backtrace for more info)

How to reslove this?


Solution

  • I believe tuples are not currently allowed because wasm-bindgen is waiting for tuples to be added to javascript so there isnt future inconstancy/breakage between rust and js. There is an open issue on wasm-bindgen asking for tuples and fixed-sized arrays here.

    For now, the best approach is probably to just create a tuple struct.

    #[wasm_bindgen]
    pub struct Coordinates(pub usize, pub usize);
    

    Then you can deconstruct it in javascript the same way.

    const [x, y] = canvasData.index_to_coordinate(100)
    

    Or use a struct with named fields and deconstruct the object

    #[wasm_bindgen]
    pub struct Coordinates{
       pub x: usize,
       pub y: usize
    }
    
    const {x, y} = canvasData.index_to_coordinate(100)