#![feature(futures_api)]
#![deny(warnings)]
use std::{
future::Future,
marker::Unpin,
pin::Pin,
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
task::{LocalWaker, Poll, Waker},
};
use pin_project::unsafe_project;
#[derive(Debug)]
struct CancelableFutureState {
is_cancelled: AtomicBool,
waker: Mutex<Option<Waker>>,
}
#[unsafe_project]
#[derive(Debug)]
#[must_use = "Futures do nothing unless polled"]
pub struct CancelableFuture<A, B> {
state: Arc<CancelableFutureState>,
#[pin]
future: Option<A>,
when_cancelled: Option<B>,
}
impl<A, B> Unpin for CancelableFuture<A, B> where A: Unpin {}
impl<A, B> Future for CancelableFuture<A, B>
where
A: Future,
B: FnOnce() -> A::Output,
{
type Output = A::Output;
fn poll(self: Pin<&mut Self>, waker: &LocalWaker) -> Poll<Self::Output> {
let this = self.project();
if this.state.is_cancelled.load(Ordering::SeqCst) {
Pin::set(this.future, None);
let callback = this.when_cancelled.take().unwrap();
Poll::Ready(callback())
} else {
match this.future.as_pin_mut().unwrap().poll(waker) {
Poll::Pending => {
*this.state.waker.lock().unwrap() = Some(waker.clone().into_waker());
Poll::Pending
}
a => a,
}
}
}
}