forky_web/dom_utils/
future_timeout.rs

1use crate::timeout_reject;
2use anyhow::Result;
3use js_sys::Array;
4use js_sys::Promise;
5use std::cell::RefCell;
6use std::future::Future;
7use std::rc::Rc;
8use std::time::Duration;
9use wasm_bindgen::JsValue;
10use wasm_bindgen::UnwrapThrowExt;
11use wasm_bindgen_futures::spawn_local;
12use wasm_bindgen_futures::JsFuture;
13
14
15pub async fn future_timeout<F, Fut, O>(fut: F, duration: Duration) -> Result<O>
16where
17	F: 'static + FnOnce() -> Fut,
18	Fut: Future<Output = O>,
19	O: 'static,
20{
21	let out = Rc::<RefCell<Option<O>>>::default();
22
23	let mut fut = Some(fut);
24	let out2 = out.clone();
25	let prom = Promise::new(&mut move |resolve, _reject| {
26		let fut = fut.take().unwrap_throw();
27		let out = out2.clone();
28		spawn_local(async move {
29			let result = fut().await;
30			*out.borrow_mut() = Some(result);
31			resolve.call0(&JsValue::NULL).unwrap();
32		});
33	});
34	let timeout = timeout_reject(duration);
35
36	let arr = Array::new();
37	arr.push(&prom);
38	arr.push(&timeout);
39
40	match JsFuture::from(Promise::race(&arr)).await {
41		Ok(_) => Ok(out.take().unwrap()),
42		Err(_) => Err(anyhow::anyhow!("Timeout")),
43	}
44}