Wasm-bindgen: Unable to use closures

Created on 1 Sep 2018  路  6Comments  路  Source: rustwasm/wasm-bindgen

I am trying to use addEventListener using wasm-bindgen, but it's not working. I tried this:

#[wasm_bindgen]
extern {
    /*...*/
    #[wasm_bindgen(method, js_name = addEventListener)]
    fn add_event_listener(this: &Element, ev_type: &str, listener: &Closure<FnMut()>);
}
/*...*/
#[wasm_bindgen]
pub fn initialize(_ {
    let a = Closure::new(foo.solve);
    document.query_selector("#solve").add_event_listener("click", &a);
}

But I got the following error:

error[E0615]: attempted to take value of method `solve` on type `foo`
  |
  = help: maybe a `()` to call it is missing?

error: aborting due to previous error

For more information about this error, try `rustc --explain E0615`.
error: Could not compile `foobar`.

But the example here uses a similar example. When I changed the foo.solve to move || {foo.solve()}, I got the following error:

error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0525`.
error: Could not compile `foobar`.

Most helpful comment

All 6 comments

In the example, fn update_time() is a function. In your code, solve is a method of foo! So there is some kind of... difference!
I don't know enough about move || {foo.solve()} to say anything about it!

In examples/closures, I add this:

struct Counter {
    clicks: u32,
}
impl Counter{
    fn count(&mut self){
        self.clicks += 2;
    }
}

Then use it instead of clicks:

    //let mut clicks = 0;
    let mut counter = Counter{clicks:0};
    let b = Closure::new(move || {
        //clicks += 1;
        counter.count();
        document
            .get_element_by_id("num-clicks")
            .set_inner_html(&counter.clicks.to_string());
    });

It works, hope it help you!

@limira After reading your answers, I tried both the method example you gave _and_ a regular function defined inside that function exactly like the one in examples/closures. Both of them compile, but give this error in the JS console:

Uncaught Error: closure invoked recursively or destroyed already
    at Module.__wbindgen_throw (foo.js:172)
    at __wbindgen_throw (main.js:77)
    at wasm_bindgen::throw::hc87cb30c4d40aef9 (:8080/wasm-function[188]:86)
    at _$LT$$LP$dyn$u20$core..ops..function..FnMut$LP$$RP$$u20$$u2b$$u20$$u27$static$RP$$u20$as$u20$wasm_bindgen..closure..WasmClosure$GT$::invoke_fn::invoke::h413d11663b64255b (:8080/wasm-function[196]:80)
    at Function.cbarg3 (foo.js:124)

@limira Thanks a lot! Now it works - I did indeed miss that.

Sounds like it's working well now, thanks @limira for the help!

Was this page helpful?
0 / 5 - 0 ratings