use std::any::Any;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use async_task::FallibleTask;
use moonpool_core::JoinError;
use parking_lot::Mutex;
use super::TaskMeta;
pub(crate) type TaskResult<T> = Result<T, Box<dyn Any + Send>>;
#[derive(Debug)]
pub struct JoinHandle<T> {
inner: Mutex<Option<FallibleTask<TaskResult<T>, TaskMeta>>>,
}
impl<T> JoinHandle<T> {
pub(crate) fn new(task: FallibleTask<TaskResult<T>, TaskMeta>) -> Self {
Self {
inner: Mutex::new(Some(task)),
}
}
#[must_use]
pub fn is_finished(&self) -> bool {
match self.inner.lock().as_ref() {
Some(task) => task.is_finished(),
None => true,
}
}
pub fn abort(&self) {
let mut inner = self.inner.lock();
if inner.as_ref().is_some_and(|task| !task.is_finished()) {
drop(inner.take());
}
}
}
impl<T> Future for JoinHandle<T> {
type Output = Result<T, JoinError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut inner = self.inner.lock();
match inner.as_mut() {
None => Poll::Ready(Err(JoinError::Cancelled)),
Some(task) => match Pin::new(task).poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(Err(JoinError::Cancelled)),
Poll::Ready(Some(Ok(output))) => Poll::Ready(Ok(output)),
Poll::Ready(Some(Err(_panic_payload))) => Poll::Ready(Err(JoinError::Panicked)),
},
}
}
}
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
if let Some(task) = self.inner.lock().take() {
task.detach();
}
}
}
#[derive(Debug)]
pub struct YieldNow {
yielded: bool,
}
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
#[must_use = "futures do nothing unless awaited"]
pub fn yield_now() -> YieldNow {
YieldNow { yielded: false }
}
#[must_use = "futures do nothing unless awaited"]
pub fn until_stalled() -> YieldNow {
assert!(
!super::in_task(),
"until_stalled() is driver-only; tasks must use executor::yield_now()"
);
YieldNow { yielded: false }
}