nusa/dom_events/
dom_event.rs1use 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}