nusa/dom_events/
dom_event.rs

1use async_std::sync::{Arc, Mutex};
2use std::collections::VecDeque;
3use std::future::Future;
4use std::pin::Pin;
5use std::task::{Context, Poll, Waker};
6use wasm_bindgen::{prelude::*, JsCast};
7
8pub struct DomEvent {
9    state: Arc<Mutex<State>>,
10}
11
12pub struct DomEventPoller {
13    state: Arc<Mutex<State>>,
14}
15
16struct State {
17    event_queue: VecDeque<web_sys::Event>,
18    waker: Option<Waker>,
19}
20
21impl DomEvent {
22    pub fn new(target: &web_sys::EventTarget, event_type: &str) -> Self {
23        let state = Arc::new(Mutex::new(State {
24            event_queue: VecDeque::new(),
25            waker: None,
26        }));
27
28        let a = Closure::wrap(Box::new({
29            let state = Arc::clone(&state);
30            move |e| {
31                let state = Arc::clone(&state);
32                wasm_bindgen_futures::spawn_local(async move {
33                    let mut state = state.lock_arc().await;
34                    state.event_queue.push_back(e);
35                    if let Some(waker) = state.waker.take() {
36                        waker.wake();
37                    }
38                });
39            }
40        }) as Box<dyn FnMut(web_sys::Event)>);
41        let _ = target.add_event_listener_with_callback_and_bool(
42            event_type,
43            a.as_ref().unchecked_ref(),
44            true,
45        );
46        a.forget();
47
48        Self { state }
49    }
50
51    pub fn poll(&self) -> DomEventPoller {
52        DomEventPoller {
53            state: Arc::clone(&self.state),
54        }
55    }
56}
57
58impl Future for DomEventPoller {
59    type Output = web_sys::Event;
60
61    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
62        if let Some(mut state) = self.as_mut().state.try_lock_arc() {
63            state.waker = Some(cx.waker().clone());
64            if let Some(event) = state.event_queue.pop_front() {
65                return Poll::Ready(event);
66            }
67        }
68        Poll::Pending
69    }
70}