2

I have a Rust program forked from the WASM-Bindgen "canvas" example. I'm trying to call some Rust code on every JavaScript onmousemove Event for the Canvas Element. My code currently creates the DOM event successfully (as it seems). However, on every event that fires, the Firefox developer edition developer tools' console shows an error:

Uncaught Error: closure invoked recursively or destroyed already

Here's part of my code:

use std::f64;
use std::sync;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

mod canvas_manager;
use canvas_manager::CanvasManager;

#[wasm_bindgen(start)]
pub fn start() {
    let document = web_sys::window().unwrap().document().unwrap();
    let canvas = document.get_element_by_id("canvas").unwrap();
    let canvas: web_sys::HtmlCanvasElement = canvas
        .dyn_into::<web_sys::HtmlCanvasElement>()
        .map_err(|_| ())
        .unwrap();

    let manager = CanvasManager::new(canvas, 480, 480);

    manager.fill_rect_with_color(210, 12, 60, 6, "#444");
    
    manager.fill_rect_with_color(210, 462, 60, 6, "#444");
    
    manager.fill_rect_with_color(236, 236, 8, 8, "#999");

    manager.clear_canvas();

    let xPos= sync::Arc::from(sync::Mutex::new(Box::new(0f64)));

    let xPosCloned = xPos.clone();

    let a = Closure::wrap(Box::new(move || {
        let mut xPosBox = xPosCloned.lock().unwrap();
        **xPosBox += 1f64;
        //web_sys::console::log_1(&JsValue::from_f64(2.5f64));
    }) as Box<dyn FnMut()>);

    manager.canvas.set_onmousemove(Some(a.as_ref().unchecked_ref()));
}

Supermath101
  • 417
  • 3
  • 10
  • Hi, this is Mr. Russ ;-). I see you have an answer to your question. It is common courtesy on Stack Overflow to upvote it/accept it if it meets your requirements, or comment on it if it doesn't. :-) I'm sure the answerer would appreciate it. :-) – Russ J Aug 30 '20 at 23:09

1 Answers1

1

In provided code a will be dropped at the end of start().

You can fix that via a.forget() but then you'll introduce memory leak.

let a = Closure::wrap(Box::new(move || {
    let mut xPosBox = xPosCloned.lock().unwrap();
    **xPosBox += 1f64;
    //web_sys::console::log_1(&JsValue::from_f64(2.5f64));
}) as Box<dyn FnMut()>);

manager.canvas.set_onmousemove(Some(a.as_ref().unchecked_ref()));
a.forget();

Please take a look at the good answer how to avoid memory leaking.

MaxV
  • 2,601
  • 3
  • 18
  • 25