Search code examples
rustwebassemblywasm-bindgenrust-wasm

Rust Wasm Bindgen returns object but gets a number


today while doing some rust wasm vs js speed benchmarking with wasm-bindgen, I ran into a problem.

I had made a simple struct as you can see here: enter image description here

I used this struct in a simple function called gimmeDirections as shown here: enter image description here

After compiling this into browser javascript, I looked into the .d.ts file that was compiled into it and noticed that the gimmeDirections function returned a number. enter image description here

even though in the js, it states in the JSDOC that it returned the class of XY which was defined earlier in the compiled code. enter image description here

here is the class:

export class XY {

    static __wrap(ptr) {
        const obj = Object.create(XY.prototype);
        obj.ptr = ptr;

        return obj;
    }

    free() {
        const ptr = this.ptr;
        this.ptr = 0;

        wasm.__wbg_xy_free(ptr);
    }
    /**
    * @returns {number}
    */
    get x() {
        var ret = wasm.__wbg_get_xy_x(this.ptr);
        return ret;
    }
    /**
    * @param {number} arg0
    */
    set x(arg0) {
        wasm.__wbg_set_xy_x(this.ptr, arg0);
    }
    /**
    * @returns {number}
    */
    get y() {
        var ret = wasm.__wbg_get_xy_y(this.ptr);
        return ret;
    }
    /**
    * @param {number} arg0
    */
    set y(arg0) {
        wasm.__wbg_set_xy_y(this.ptr, arg0);
    }
}

after being very confused, due to the fact of how the typescript said it would return a number but the js said it would return a class, I decided to run it... and got a number back. enter image description here

The object below is my javascript function running identical code for the benchmark, as you can see, I got an object, not a number.

Here is my JS code:

import * as funcs from './wasm/wildz.js';
// compiled wasm js file
function directionsJS(x, y) {
    let xX = x;
    let yY = y;
    if (Math.abs(xX) === Math.abs(yY)) {
        xX /= Math.SQRT2;
        yY /= Math.SQRT2;
    }
    return {
        x: x,
        y: yY
    };
}
(async() => {
    const game = await funcs.default();
    console.time('Rust Result'); console.log(game.gimmeDirections(10, 10)); 
    console.timeEnd('Rust Result'); console.time('JS Result'); 
    console.log(directionsJS(10, 10)); console.timeEnd('JS Result');
})();

I'm still very confused on why it's returning a number when clearly I'm returning a object. Help is much needed, and appreciated


Solution

  • Much of this and more is explained in Exporting a struct to JS in the wasm-bindgen guide, but I'll summarize.

    Rust structs are "returned" by allocating space for them dynamically and returning a pointer to it. What you're seeing, in regards to the function returning number, is the "raw" ffi function that binds the JS runtime and wasm module. It just returns that pointer value.

    The generated XY Javascript class is a wrapper around that pointer value and provides functions for interacting with it. The generated gimmeDirections function is a wrapper around that wasm module call that creates that class.