wasm_repeated_animation_frame/
lib.rs1use async_channel::{Receiver, Sender};
2use futures::{future::select_all, FutureExt};
3use js_sys::Function;
4use manual_future::ManualFuture;
5use wasm_bindgen::{closure::Closure, JsCast};
6use wasm_bindgen_futures::spawn_local;
7use web_sys::window;
8
9pub struct RafLoopCanceler {
10 sender: Sender<()>,
11}
12
13impl RafLoopCanceler {
14 pub async fn cancel(&self) {
15 self.sender.send(()).await.unwrap();
16 }
17}
18
19pub struct RafLoop {
20 handle: Option<i32>,
21 receiver: Receiver<()>,
22}
23
24impl RafLoop {
25 pub fn new() -> (RafLoop, RafLoopCanceler) {
26 let (sender, receiver) = async_channel::bounded::<()>(1);
27 (
28 RafLoop {
29 handle: None,
30 receiver,
31 },
32 RafLoopCanceler { sender },
33 )
34 }
35
36 pub fn cancel(&mut self) {
37 window()
38 .unwrap()
39 .cancel_animation_frame(self.handle.unwrap())
40 .unwrap();
41 self.handle = None;
42 }
43
44 pub async fn next(&mut self) -> bool {
45 let (future, completer) = ManualFuture::<()>::new();
46 let closure = Closure::once(Box::new(move || {
47 spawn_local(completer.complete(()));
48 }) as Box<dyn FnOnce()>);
49 let handle = window()
50 .unwrap()
51 .request_animation_frame(&(closure.into_js_value().unchecked_into::<Function>()))
52 .unwrap();
53 self.handle = Some(handle);
54 enum Event {
55 Stop,
56 Raf,
57 }
58 let (event, _, _) = select_all(vec![
59 async {
60 future.await;
61 Event::Raf
62 }
63 .boxed(),
64 async {
65 self.receiver.recv().await.unwrap();
66 Event::Stop
67 }
68 .boxed(),
69 ])
70 .await;
71 match event {
72 Event::Raf => true,
73 Event::Stop => false,
74 }
75 }
76}