libp2p_webtransport_websys/
fused_js_promise.rs

1use std::{
2    future::Future,
3    pin::Pin,
4    task::{ready, Context, Poll},
5};
6
7use futures::FutureExt;
8use js_sys::Promise;
9use wasm_bindgen::JsValue;
10use wasm_bindgen_futures::JsFuture;
11
12/// Convenient wrapper to poll a promise to completion.
13///
14/// # Panics
15///
16/// Panics if polled and promise is not initialized. Use `maybe_init` if unsure.
17#[derive(Debug)]
18pub(crate) struct FusedJsPromise {
19    promise: Option<JsFuture>,
20}
21
22impl FusedJsPromise {
23    /// Creates new uninitialized promise.
24    pub(crate) fn new() -> Self {
25        FusedJsPromise { promise: None }
26    }
27
28    /// Initialize promise if needed
29    pub(crate) fn maybe_init<F>(&mut self, init: F) -> &mut Self
30    where
31        F: FnOnce() -> Promise,
32    {
33        if self.promise.is_none() {
34            self.promise = Some(JsFuture::from(init()));
35        }
36
37        self
38    }
39
40    /// Checks if promise is already running
41    pub(crate) fn is_active(&self) -> bool {
42        self.promise.is_some()
43    }
44}
45
46impl Future for FusedJsPromise {
47    type Output = Result<JsValue, JsValue>;
48
49    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
50        let val = ready!(self
51            .promise
52            .as_mut()
53            .expect("FusedJsPromise not initialized")
54            .poll_unpin(cx));
55
56        // Future finished, drop it
57        self.promise.take();
58
59        Poll::Ready(val)
60    }
61}