-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert Closure
to js_sys::Function
#1140
Comments
Why don't you just store the |
If I use the i.e. Whereas if I use a function I can make any type of closure that I want since they'll all become Allowing for arbitrary event listeners to be stored together in, say, a HashMap of event names strings to event handlers Let me know if I'm missing something! |
Oh, I see. I don't know how to convert it to a |
@chinedufn Using Using However, keep in mind that when the So I really don't recommend doing that, instead you're better off finding a way to store the In order to store the If you need even more dynamicism, you might be able to convert the Closures into Using trait objects like this is a common way to do polymorphism in Rust. It has a small performance cost, but given your needs I think it's quite reasonable. |
Woah. Incredibly helpful. This should give me everything that I need. Thanks a lot both! |
Great idea! Just a little less readable compare to |
This comment was marked as abuse.
This comment was marked as abuse.
So, if I'm understanding, your goal is to be able to stop a RAF loop from JS? If so, can you expose a function to your JS.. let's call it // should_loop: Rc::new(RefCell::new(true));
fn stop (&self) {
*self.should_loop.borrow_mut() = false;
} Give your RAF loop access to an if *should_loop.borrow() {
request_animation_frame(g.borrow().as_ref().unwrap());
} Very quick and dirty pseudocode of course - but hopefully is draws the picture here. Does that make sense? Do that fit your use case? Anything that I can clarify? |
This comment was marked as abuse.
This comment was marked as abuse.
Yeah more or less Because the alternative is that each time you call RAF you get a new id that can be used to cancel that specific call to RAF, so you'd need to pass that pack to JS everytime so that at the moment that you wanted to cancel you'd have the right ID to cancel. Which would be a hassle. |
This comment was marked as abuse.
This comment was marked as abuse.
What do you mean by break out? Mind explaining exactly what you're trying to do and I'll see if I can lend some tips? Cheers! |
This comment was marked as abuse.
This comment was marked as abuse.
This comment was marked as abuse.
This comment was marked as abuse.
@dakom As a general rule, if you're using I haven't looked through all of your code, but I would write it something like this: use web_sys::UiEvent;
pub struct OnResize {
_listener: EventListener<'static, UiEvent>,
}
impl OnResize {
pub fn new<F>(mut f: F) -> Result<Self, JsValue> where F: FnMut(u32, u32) + 'static {
let mut on_resize = move || -> Result<(), JsValue> {
let window = get_window()?;
let size = get_window_size(&window)?;
f(size.width as u32, size.height as u32);
Ok(())
};
on_resize()?;
Ok(OnResize {
_listener: EventListener::new(&*(get_window()?), "resize", move |_| {
on_resize().unwrap();
}),
})
}
} (Using the And now you can use it like this: let webgl_renderer = webgl_renderer.clone();
let scene = scene.clone();
OnResize::new(move |width, height| {
webgl_renderer.borrow_mut().resize(width, height);
scene.borrow_mut().resize(width, height);
})? When the Keep in mind that looking up the window's size causes a browser reflow, which can be extremely slow or fast (depending on when exactly you do it). And here is how I would write a RAF loop: use std::rc::Rc;
use std::cell::RefCell;
use wasm_bindgen::JsCast;
use web_sys::window;
struct Inner {
id: i32,
closure: Closure<FnMut(f64)>,
}
pub struct Raf {
inner: Rc<RefCell<Option<Inner>>>,
}
impl Raf {
pub fn new<F>(mut f: F) -> Self where F: FnMut(f64) + 'static {
let inner: Rc<RefCell<Option<Inner>>> = Rc::new(RefCell::new(None));
let closure = {
let inner = inner.clone();
Closure::wrap(Box::new(move |time| {
if let Some(inner) = inner.borrow_mut().as_mut() {
inner.id = window().unwrap().request_animation_frame(inner.closure.as_ref().unchecked_ref()).unwrap();
}
f(time);
}) as Box<FnMut(f64)>)
};
*inner.borrow_mut() = Some(Inner {
id: window().unwrap().request_animation_frame(closure.as_ref().unchecked_ref()).unwrap(),
closure,
});
Raf { inner }
}
}
impl Drop for Raf {
fn drop(&mut self) {
// This uses take() so that it cleans up the Closure
if let Some(inner) = self.inner.borrow_mut().take() {
window().unwrap().cancel_animation_frame(inner.id).unwrap();
}
}
} Then you use it like this: Raf::new(move |time_stamp| {
let mut scene = scene.borrow_mut();
scene.tick(time_stamp);
}) When the As for stopping it from JS, I'm not sure exactly why you need to do that, and I don't have much experience in that area, but I would pass a struct to JS, and JS can then call the #[wasm_bindgen]
pub struct State {
raf: Raf,
on_resize: OnResize,
}
#[wasm_bindgen]
impl State {
pub fn new() -> Self {
Self {
raf: Raf::new(...),
on_resize: OnResize::new(...),
}
}
} const state = State.new();
// use state in JS
state.free(); |
I know that we can convert a
Closure
into an&js_sys::Function
usingmy_closure.as_ref().unchecked_ref()
.. But I can't seem to figure out how to cast it into ajs_sys::Function
.(My use case is trying to store the
Function
in a struct without worrying about lifetimes.)Is this possible?
The text was updated successfully, but these errors were encountered: