use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use std::{
sync::Arc,
task::{Wake, Waker},
thread,
};
struct ThreadWaker(thread::Thread);
impl Wake for ThreadWaker {
#[inline]
fn wake(self: Arc<Self>) {
self.0.unpark();
}
#[inline]
fn wake_by_ref(self: &Arc<Self>) {
self.0.unpark();
}
}
pub fn block_on<F: Future>(f: F) -> F::Output {
let mut f = Box::pin(f);
let waker = Waker::from(Arc::new(ThreadWaker(thread::current())));
let mut cx = Context::from_waker(&waker);
loop {
match f.as_mut().poll(&mut cx) {
Poll::Ready(val) => return val,
Poll::Pending => thread::park(),
}
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct YieldNow(pub bool);
impl Future for YieldNow {
type Output = ();
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
Poll::Ready(())
} else {
self.0 = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
#[inline(always)]
pub const fn yield_now() -> YieldNow {
YieldNow(false)
}
#[cfg(test)]
mod tests {
use core::task::Waker;
use std::{
sync::atomic::{AtomicBool, Ordering},
time::Duration,
};
use super::*;
#[test]
fn test_yield_now() {
let mut y = yield_now();
let waker = Waker::noop();
let mut cx = Context::from_waker(waker);
assert_eq!(Pin::new(&mut y).poll(&mut cx), Poll::Pending);
assert_eq!(Pin::new(&mut y).poll(&mut cx), Poll::Ready(()));
assert_eq!(Pin::new(&mut y).poll(&mut cx), Poll::Ready(()));
assert_eq!(YieldNow::default(), yield_now());
}
#[test]
fn test_block_on() {
assert_eq!(block_on(async { 3 }), 3);
block_on(yield_now());
}
#[test]
fn test_block_on_cross_thread_wake() {
let flag = Arc::new(AtomicBool::new(false));
let f_flag = Arc::clone(&flag);
let val = block_on(async move {
let handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(1));
f_flag.store(true, Ordering::Release);
});
struct WaitFlag(Arc<AtomicBool>);
impl Future for WaitFlag {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0.load(Ordering::Acquire) {
return Poll::Ready(());
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
WaitFlag(flag).await;
handle.join().expect("子线程不 panic");
42
});
assert_eq!(val, 42);
}
}