Wasm-bindgen: How to call function on an object?

Created on 7 Apr 2019  路  8Comments  路  Source: rustwasm/wasm-bindgen

Summary

Given a js_sys::Object, how do you call one of its functions?

Additional Details

Specifically I get a webgl extension via https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.WebGlRenderingContext.html#method.get_extension

After extracting the inner object, I want to call its functions from Rust (e.g. https://developer.mozilla.org/en-US/docs/Web/API/ANGLE_instanced_arrays#Methods)

How do I do this? :)

question

Most helpful comment

@dakom You can use Reflect::get to access the members and then Reflect::apply to call them.

But that's pretty terrible (and slow), so a much better approach is to create some bindings for it:

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_name = ANGLEInstancedArrays)]
    type AngleInstancedArrays;

    #[wasm_bindgen(method, getter, js_name = VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)]
    fn vertex_attrib_array_divisor_angle(this: &AngleInstancedArrays) -> i32;

    #[wasm_bindgen(method, catch, js_name = drawArraysInstancedANGLE)]
    fn draw_arrays_instanced_angle(this: &AngleInstancedArrays, mode: u32, first: i32, count: i32, primcount: i32) -> Result<(), JsValue>;

    // TODO offset should be i64
    #[wasm_bindgen(method, catch, js_name = drawElementsInstancedANGLE)]
    fn draw_elements_instanced_angle(this: &AngleInstancedArrays, mode: u32, count: i32, type_: u32, offset: i32, primcount: i32) -> Result<(), JsValue>;

    #[wasm_bindgen(method, js_name = vertexAttribDivisorANGLE)]
    fn vertex_attrib_divisor_angle(this: &AngleInstancedArrays, index: u32, divisor: u32);
}

Then you can convert your Object into an AngleInstancedArrays by using this:

let foo = foo.unchecked_into::<AngleInstancedArrays>();

@alexcrichton @fitzgen Can we somehow auto-generate bindings for the WebGL extensions? There is IDL for it.

All 8 comments

@dakom You can use Reflect::get to access the members and then Reflect::apply to call them.

But that's pretty terrible (and slow), so a much better approach is to create some bindings for it:

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_name = ANGLEInstancedArrays)]
    type AngleInstancedArrays;

    #[wasm_bindgen(method, getter, js_name = VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)]
    fn vertex_attrib_array_divisor_angle(this: &AngleInstancedArrays) -> i32;

    #[wasm_bindgen(method, catch, js_name = drawArraysInstancedANGLE)]
    fn draw_arrays_instanced_angle(this: &AngleInstancedArrays, mode: u32, first: i32, count: i32, primcount: i32) -> Result<(), JsValue>;

    // TODO offset should be i64
    #[wasm_bindgen(method, catch, js_name = drawElementsInstancedANGLE)]
    fn draw_elements_instanced_angle(this: &AngleInstancedArrays, mode: u32, count: i32, type_: u32, offset: i32, primcount: i32) -> Result<(), JsValue>;

    #[wasm_bindgen(method, js_name = vertexAttribDivisorANGLE)]
    fn vertex_attrib_divisor_angle(this: &AngleInstancedArrays, index: u32, divisor: u32);
}

Then you can convert your Object into an AngleInstancedArrays by using this:

let foo = foo.unchecked_into::<AngleInstancedArrays>();

@alexcrichton @fitzgen Can we somehow auto-generate bindings for the WebGL extensions? There is IDL for it.

I think this is a duplicate of https://github.com/rustwasm/wasm-bindgen/issues/1257, so I'm going to close in favor of that (but cc @Pauan's excellent answer over there) and the general problem for supporting this is tracked at https://github.com/rustwasm/wasm-bindgen/issues/893 which I think https://github.com/rustwasm/wasm-bindgen/pull/1405 may help start paving the path towards implementing.

[wasm_bindgen(js_name = ANGLEInstancedArrays)]

type AngleInstancedArrays;

@Pauan Can you please explain a little more what's going on there?

The section from The Rust Book that talks about type aliases doesn't seem to mention creating a type alias to nothing...

e.g. all the examples there have type foo = bar and I'm not clear on what's happening with just type foo

Sorry for another newbie question... and I realize this might not be specific to wasm-bindgen, but I'm thinking maybe the annotation above it is doing some magic?

@dakom It's not a type alias, it's an extern type (it's inside of an extern block).

It's something specific to the wasm-bindgen macro, you can't use it outside of wasm-bindgen (there is experimental support for it in Rust itself, but it's used for C, not JS).

It basically says "create a new type in Rust, but it's actually a JS type, so internally it just uses JsValue".

It's basically just used to wrap JS types into statically type safe Rust types.

So in the above code, type AngleInstancedArrays; will get translated into something like struct AngleInstancedArrays(JsValue), except with some additional wasm-bindgen stuff.

@Pauan I just wanted to thank you for the above information... Using your documentation I was able to achieve the following (maybe this helps someone else)...

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_name = EXT_texture_filter_anisotropic)]
    type ExtTextureFilterAnisotropic;
}
let mut extension = ctx.gl.get_extension("EXT_texture_filter_anisotropic").unwrap().unwrap()
            .unchecked_into::<ExtTextureFilterAnisotropic>();

        let property = JsValue::from_str("MAX_TEXTURE_MAX_ANISOTROPY_EXT");
        let value = js_sys::Reflect::get(&extension, &property);


        console::log_1(&extension);
        console::log_1(&property);
        console::log_1(&value.unwrap());

image
@alexcrichton The team has done a tremendous job of the WASM bind-gen and in a very short period of time. I looked at this project three months ago and thought, "not ready yet" and now I feel it is certainly ready. Sure it will always need work and the more automation the better but this is top shelf guys... well done.
/W

I'm having a bit of trouble trying to figure out how to pass more complex objects into the extension. for example something like this to allow vertex arrays via the "OES_vertex_array_object" extension, which should have the same signature as webgl2's native create_vertex_array() / bind_vertex_array()

it seems create_vertex_array_oes() is working fine, but when I try to pass that into bind_vertex_array_oes() I get errors.

Also tried different approaches (not using option, not using refs, etc.)

Any help is appreciated, thanks!

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_name = OesVertexArray)]
    pub type OesVertexArray;

    #[wasm_bindgen(method, getter, js_name = createVertexArrayOES)]
    pub fn create_vertex_array_oes(this: &OesVertexArray) -> Option<WebGlVertexArrayObject>;

    #[wasm_bindgen(method, js_name = bindVertexArrayOES)]
    pub fn bind_vertex_array_oes(this: &OesVertexArray, target:Option<&WebGlVertexArrayObject>);

}

@dakom can you open a new issue with details as well to the error you're seeing? Some code to reproduce would also be great!

Nevermind - I see this extension is actually bundled as part of web-sys now :)

https://docs.rs/web-sys/0.3.23/web_sys/struct.OesVertexArrayObject.html

Was this page helpful?
0 / 5 - 0 ratings