use futures::FutureExt;
use futures::future::{BoxFuture, LocalBoxFuture};
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{Context, Poll};
#[derive(Clone)]
struct ReadyInner {
ready: Arc<AtomicBool>,
}
impl ReadyInner {
fn new() -> Self {
Self {
ready: Arc::new(AtomicBool::new(false)),
}
}
fn ready(&self) -> bool {
self.ready.load(Ordering::SeqCst)
}
fn notify(&self) {
self.ready.store(true, Ordering::SeqCst);
}
}
pub struct ReadyPollFuture<'a, T> {
ready: ReadyInner,
future: BoxFuture<'a, T>,
}
impl<'a, T> Drop for ReadyPollFuture<'a, T> {
fn drop(&mut self) {
self.ready.notify();
}
}
impl<'a, T> Future for ReadyPollFuture<'a, T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = self.future.poll_unpin(cx);
if result.is_ready() {
self.ready.notify();
}
result
}
}
pub struct ReadyPoll {
ready: ReadyInner,
}
impl ReadyPoll {
pub fn ready(&self) -> bool {
self.ready.ready()
}
}
pub fn ready_poll<'a, T, F>(future: F) -> (ReadyPollFuture<'a, T>, ReadyPoll)
where
F: Future<Output = T> + Send + 'a,
{
let ready = ReadyInner::new();
let ready1 = ready.clone();
(
ReadyPollFuture {
ready,
future: Box::pin(future),
},
ReadyPoll { ready: ready1 },
)
}
pub struct LocalReadyPollFuture<'a, T> {
ready: ReadyInner,
future: LocalBoxFuture<'a, T>,
}
impl<'a, T> Drop for LocalReadyPollFuture<'a, T> {
fn drop(&mut self) {
self.ready.notify();
}
}
impl<'a, T> Future for LocalReadyPollFuture<'a, T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let result = self.future.poll_unpin(cx);
if result.is_ready() {
self.ready.notify();
}
result
}
}
pub fn local_ready_poll<'a, T, F>(future: F) -> (LocalReadyPollFuture<'a, T>, ReadyPoll)
where
F: Future<Output = T> + 'a,
{
let ready = ReadyInner::new();
let ready1 = ready.clone();
(
LocalReadyPollFuture {
ready,
future: Box::pin(future),
},
ReadyPoll { ready: ready1 },
)
}