iota_sdk_graphql_client/
wait.rs1use std::{future::Future, time::Duration};
9
10#[cfg(not(target_arch = "wasm32"))]
12pub(crate) async fn sleep(duration: Duration) {
13 tokio::time::sleep(duration).await;
14}
15
16#[cfg(target_arch = "wasm32")]
17pub(crate) async fn sleep(duration: Duration) {
18 wasm_time::Sleep::new(duration).await;
19}
20
21#[cfg(not(target_arch = "wasm32"))]
23pub(crate) async fn timeout<F: Future>(duration: Duration, f: F) -> Result<F::Output, Elapsed> {
24 tokio::time::timeout(duration, f).await.map_err(|_| Elapsed)
25}
26
27#[cfg(target_arch = "wasm32")]
28pub(crate) async fn timeout<F: Future>(duration: Duration, f: F) -> Result<F::Output, Elapsed> {
29 use futures::future::Either;
30 let work = std::pin::pin!(f);
31 let timer = std::pin::pin!(wasm_time::Sleep::new(duration));
32 match futures::future::select(work, timer).await {
33 Either::Left((v, _)) => Ok(v),
34 Either::Right((_, _)) => Err(Elapsed),
35 }
36}
37
38#[derive(Debug)]
40pub(crate) struct Elapsed;
41
42impl std::fmt::Display for Elapsed {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.write_str("deadline elapsed")
45 }
46}
47
48impl std::error::Error for Elapsed {}
49
50#[cfg(target_arch = "wasm32")]
51mod wasm_time {
52 use std::{
53 cell::Cell,
54 future::Future,
55 pin::Pin,
56 rc::Rc,
57 task::{Context, Poll, Waker},
58 time::Duration,
59 };
60
61 use wasm_bindgen::{closure::Closure, prelude::*};
62
63 #[wasm_bindgen]
64 unsafe extern "C" {
65 #[wasm_bindgen(js_name = setTimeout)]
66 fn set_timeout(callback: &js_sys::Function, ms: i32) -> JsValue;
67 #[wasm_bindgen(js_name = clearTimeout)]
68 fn clear_timeout(handle: &JsValue);
69 }
70
71 struct State {
72 fired: Cell<bool>,
73 waker: Cell<Option<Waker>>,
74 }
75
76 pub(super) struct Sleep {
79 state: Rc<State>,
80 handle: Option<JsValue>,
81 _closure: Option<Closure<dyn FnMut()>>,
82 }
83
84 impl Sleep {
85 pub(super) fn new(duration: Duration) -> Self {
86 let state = Rc::new(State {
87 fired: Cell::new(false),
88 waker: Cell::new(None),
89 });
90 let cb_state = state.clone();
91 let closure: Closure<dyn FnMut()> = Closure::new(move || {
92 cb_state.fired.set(true);
93 if let Some(w) = cb_state.waker.take() {
94 w.wake();
95 }
96 });
97 let ms = duration.as_millis().min(i32::MAX as u128) as i32;
98 let handle = set_timeout(closure.as_ref().unchecked_ref(), ms);
99 Self {
100 state,
101 handle: Some(handle),
102 _closure: Some(closure),
103 }
104 }
105 }
106
107 impl Future for Sleep {
108 type Output = ();
109
110 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
111 if self.state.fired.get() {
112 self.handle = None;
113 Poll::Ready(())
114 } else {
115 self.state.waker.set(Some(cx.waker().clone()));
116 Poll::Pending
117 }
118 }
119 }
120
121 impl Drop for Sleep {
122 fn drop(&mut self) {
123 if let Some(handle) = self.handle.take() {
124 clear_timeout(&handle);
125 }
126 }
127 }
128}