Implementing tokio JoinHandle for wasm
Pub Date: 2023-07-22
#![allow(unused)] fn main() { use std::any::Any; use tokio::sync::oneshot; // happily surprised that a lot of tokio is just async abstractions that don't rely on the runtime. use pin_project::pin_project; use sync_wrapper::SyncWrapper; #[pin_project] pub struct JoinHandle<T> { result: Arc<Mutex<Option<Result<T, JoinError>>>>, #[pin] receiver: oneshot::Receiver<T>, } impl<T> Future for JoinHandle<T> { type Output = Result<T, JoinError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let this = self.project(); if let Ok(mut result) = this.result.lock() { if let Some(result) = result.take() { return Poll::Ready(result); } } match this.receiver.poll(cx) { Poll::Ready(result) => { let result = match result { Ok(result) => Ok(result), Err(_) => Err(JoinError::Cancelled), }; if let Ok(mut guard) = this.result.lock() { *guard = Some(result); } let mut result = match this.result.lock() { Ok(guard) => guard, Err(error) => error.into_inner(), }; Poll::Ready(result.take().unwrap()) } Poll::Pending => Poll::Pending, } } } impl<T> JoinHandle<T> { pub fn abort(&self) { if let Ok(mut guard) = self.result.lock() { *guard = Some(Err(JoinError::Cancelled)); } } } #[derive(Debug)] pub enum JoinError { Cancelled, Panic(SyncWrapper<Box<dyn Any + Send + 'static>>), } impl JoinError { pub fn is_cancelled(&self) -> bool { matches!(self, JoinError::Cancelled) } pub fn is_panic(&self) -> bool { matches!(self, JoinError::Panic(_)) } } }