use std::{
any::Any,
fmt,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
use crate::task::raw::RawTask;
pub type Result<T> = std::result::Result<T, JoinError>;
pub struct JoinError {
kind: JoinErrorKind,
}
enum JoinErrorKind {
Cancelled,
Panic(Box<dyn Any + Send + 'static>),
}
impl JoinError {
pub(crate) fn cancelled() -> Self {
Self {
kind: JoinErrorKind::Cancelled,
}
}
pub(crate) fn panic(payload: Box<dyn Any + Send + 'static>) -> Self {
Self {
kind: JoinErrorKind::Panic(payload),
}
}
pub fn is_cancelled(&self) -> bool {
matches!(self.kind, JoinErrorKind::Cancelled)
}
pub fn is_panic(&self) -> bool {
matches!(self.kind, JoinErrorKind::Panic(_))
}
pub fn into_panic(self) -> Box<dyn Any + Send + 'static> {
match self.kind {
JoinErrorKind::Panic(payload) => payload,
JoinErrorKind::Cancelled => panic!("JoinError is not a panic"),
}
}
}
impl fmt::Debug for JoinError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self.kind {
JoinErrorKind::Cancelled => "Cancelled",
JoinErrorKind::Panic(_) => "Panic",
};
f.debug_struct("JoinError").field("kind", &kind).finish()
}
}
impl fmt::Display for JoinError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
JoinErrorKind::Cancelled => f.write_str("task was cancelled"),
JoinErrorKind::Panic(_) => f.write_str("task panicked"),
}
}
}
impl std::error::Error for JoinError {}
pub struct JoinHandle<T> {
raw: RawTask,
_p: PhantomData<T>,
}
unsafe impl<T: Send> Send for JoinHandle<T> {}
unsafe impl<T: Sync> Sync for JoinHandle<T> {}
impl<T> JoinHandle<T> {
pub(super) fn new(raw: RawTask) -> JoinHandle<T> {
JoinHandle { raw, _p: PhantomData }
}
pub fn is_finished(&self) -> bool {
let state = self.raw.header().state.get_snapshot();
state.is_complete()
}
pub fn abort(&self) {
self.raw.cancel();
}
}
impl<T> Unpin for JoinHandle<T> {}
impl<T> Future for JoinHandle<T> {
type Output = Result<T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut ret = Poll::Pending;
self.raw.try_read_output(&mut ret as *mut _ as *mut (), cx.waker());
ret
}
}
impl<T> Drop for JoinHandle<T> {
fn drop(&mut self) {
if self.raw.header().state.drop_join_handle_fast().is_ok() {
return;
}
self.raw.drop_join_handle();
}
}