use crate::{LocalWaker, Waker};
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
pub struct JoinHandle<T: Future> {
inner: Rc<JoinHandleInner<T>>,
}
impl<T: Future> JoinHandle<T> {
pub fn is_finished(&self) -> bool {
self.inner.output.borrow().is_some()
}
pub fn join(self) -> Option<T::Output> {
self.inner.output.take()
}
fn get(&self) -> Option<T::Output> {
self.inner.output.take()
}
pub(crate) fn new() -> Self {
Self {
inner: Rc::new(JoinHandleInner::new()),
}
}
pub(crate) fn inner(&self) -> &Rc<JoinHandleInner<T>> {
&self.inner
}
}
impl<T: Future> Future for JoinHandle<T> {
type Output = T::Output;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(output) = self.get() {
return Poll::Ready(output);
}
self.inner
.waker
.replace(Some(LocalWaker::waker(ctx).clone()));
Poll::Pending
}
}
pub(crate) struct JoinHandleInner<T: Future> {
output: RefCell<Option<T::Output>>,
waker: RefCell<Option<Waker>>,
}
impl<T: Future> JoinHandleInner<T> {
fn new() -> Self {
Self {
output: RefCell::new(None),
waker: RefCell::new(None),
}
}
pub(crate) fn set_output(&self, val: T::Output) {
self.output.replace(Some(val));
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
}