use core::future::{Future, IntoFuture};
#[cfg(not(target_arch = "wasm32"))]
pub trait MaybeFuture: IntoFuture + Sized {
fn wait(self) -> Self::Output {
block_on(self.into_future())
}
}
#[cfg(not(target_arch = "wasm32"))]
impl<T: IntoFuture> MaybeFuture for T {}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn block_on<F: Future>(fut: F) -> F::Output {
use std::sync::Arc;
use std::task::{Context, Poll, Wake, Waker};
use std::thread::{self, Thread};
struct ThreadWaker(Thread);
impl Wake for ThreadWaker {
fn wake(self: Arc<Self>) {
self.0.unpark();
}
fn wake_by_ref(self: &Arc<Self>) {
self.0.unpark();
}
}
let waker = Waker::from(Arc::new(ThreadWaker(thread::current())));
let mut cx = Context::from_waker(&waker);
let mut fut = core::pin::pin!(fut);
loop {
match fut.as_mut().poll(&mut cx) {
Poll::Ready(value) => return value,
Poll::Pending => thread::park(),
}
}
}
pub(crate) struct Blocking<F>(Option<F>);
impl<F> Blocking<F> {
pub(crate) fn new(f: F) -> Self {
Blocking(Some(f))
}
}
impl<F, T> Future for Blocking<F>
where
F: FnOnce() -> T + Unpin,
{
type Output = T;
fn poll(
mut self: core::pin::Pin<&mut Self>,
_cx: &mut core::task::Context<'_>,
) -> core::task::Poll<T> {
let f = self
.0
.take()
.expect("Blocking future polled after completion");
core::task::Poll::Ready(f())
}
}