2

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

Artrix
  • 149
  • 10
  • 1
    https://idownvotedbecau.se/imageofcode – Stargateur Nov 06 '20 at 00:10
  • In short: look what `XY._wrap` does in your JavaScript, this should probably answer your question. – Cerberus Nov 06 '20 at 03:59
  • @Cerberus I still dont get it :C it seems to be creating an object out of the prototype and then assigning whatever is passed into that function – Artrix Nov 06 '20 at 04:07
  • @Artrix what are you waiting for ? the link already tell everything you need to known about the problem with the question. I will be happy to remove the downvote if the question become better. – Stargateur Nov 06 '20 at 14:33

1 Answers1

4

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.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • So I should do something like new XY(gimmeDirections(10, 10))? – Artrix Nov 06 '20 at 16:14
  • No. You've said you call it one way you get a number, you call it another way you get an object. So call it the way you get an object. You've neglected to include what you're actually doing to get those results in your post so I can't say directly what you should do. One is a member function on the module itself, the other is an exported free function. – kmdreko Nov 06 '20 at 17:02
  • 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'); – Artrix Nov 06 '20 at 22:27
  • what is `game` and what is `directionsJS`? you should add that info and the above logging sample to the original post. not including code relevant to your question (as text) makes it much harder to answer you outright and leads to these long comment threads. – kmdreko Nov 06 '20 at 22:38
  • thank you for your tips! I've added my javascript code to the question – Artrix Nov 07 '20 at 01:29
  • I don't know what `funcs.default()` is, I don't have that function when trying to build this code with wasm-pack/webpack. But if I were to guess, you should be using `funcs.gimmeDirections` instead – kmdreko Nov 09 '20 at 21:13