wasm_bindgen_spawn/
join.rs1use std::any::Any;
2use std::marker::PhantomData;
3use std::pin::Pin;
4use std::task::{Context, Poll};
5
6use crate::util::{Value, ValueReceiver, ValueReceiverAsync, WorkerPanic, WorkerResult};
7
8pub struct JoinHandle<T: Send + 'static> {
17 id: usize,
18 recv: ValueReceiver,
19 _marker: PhantomData<T>,
20}
21
22impl<T: Send + 'static> JoinHandle<T> {
23 pub(crate) fn new(id: usize, recv: ValueReceiver) -> Self {
24 Self {
25 id,
26 recv,
27 _marker: PhantomData,
28 }
29 }
30
31 pub fn join(self) -> Result<T, Box<dyn Any + Send + 'static>> {
46 handle_join_result(self.id, self.recv.recv())
47 }
48
49 pub fn is_finished(&self) -> bool {
52 self.recv.has_message() || self.recv.is_closed()
53 }
54}
55
56pub struct AsyncJoinHandle<T: Send + 'static> {
58 id: usize,
59 recv: ValueReceiverAsync,
60 _marker: PhantomData<T>,
61}
62
63impl<T: Send + 'static> IntoFuture for JoinHandle<T> {
64 type Output = Result<T, Box<dyn Any + Send + 'static>>;
65 type IntoFuture = AsyncJoinHandle<T>;
66
67 fn into_future(self) -> Self::IntoFuture {
68 AsyncJoinHandle {
69 id: self.id,
70 recv: self.recv.into_future(),
71 _marker: PhantomData,
72 }
73 }
74}
75
76impl<T: Send + 'static> Future for AsyncJoinHandle<T> {
77 type Output = Result<T, Box<dyn Any + Send + 'static>>;
78
79 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
80 let id = self.id;
81 let recv = unsafe { self.map_unchecked_mut(|s| &mut s.recv) };
83 match recv.poll(cx) {
84 Poll::Ready(x) => Poll::Ready(handle_join_result(id, x)),
85 Poll::Pending => Poll::Pending,
86 }
87 }
88}
89
90fn handle_join_result<T>(
91 id: usize,
92 result: Result<WorkerResult, oneshot::RecvError>,
93) -> Result<T, Box<dyn Any + Send + 'static>> {
94 let result = match result {
96 Ok(x) => x,
97 Err(_) => return Err(Box::new(format!("thread {id} is disconnected"))),
98 };
99 let value: Value = match result {
101 Ok(x) => x,
102 Err(WorkerPanic { payload: Some(e) }) => {
103 return Err(e);
104 }
105 Err(WorkerPanic { payload: None }) => {
106 if cfg!(panic = "unwind") {
107 return Err(Box::new(format!(
109 "thread {id} encountered a non-recoverable hard abort!",
110 )));
111 }
112 return Err(Box::new(format!("thread {id} panicked or aborted!")));
113 }
114 };
115 let value: Box<T> = unsafe { value.into_box_unchecked() };
117 Ok(*value)
118}