1use std::{fmt, panic::Location, pin::Pin, task::Context, task::Poll, task::ready};
2
3use crate::remote::RemoteJoin;
4
5type Task<T> = crate::rt::task::Task<T>;
6
7pub(crate) type SpawnLocation = &'static Location<'static>;
9
10#[derive(Debug)]
15pub struct JoinHandle<T> {
16 task: Task<T>,
17}
18
19impl<T> JoinHandle<T> {
20 pub(crate) fn new(task: Task<T>) -> Self {
21 JoinHandle { task }
22 }
23
24 pub fn cancel(self) {
26 self.task.cancel();
27 }
28
29 pub fn detach(self) {}
31
32 pub fn is_finished(&self) -> bool {
34 self.task.is_finished()
35 }
36}
37
38impl<T> Future for JoinHandle<T> {
39 type Output = Result<T, JoinError>;
40
41 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
42 self.task.poll_join(cx).map(|out| out.ok_or(JoinError))
43 }
44}
45
46#[derive(Debug)]
52pub struct RemoteJoinHandle<T> {
53 inner: Inner<T>,
54}
55
56#[derive(Debug)]
57enum Inner<T> {
58 Local(JoinHandle<T>),
59 Remote(RemoteJoin<T>),
60}
61
62impl<T> RemoteJoinHandle<T> {
63 pub(crate) fn local(task: JoinHandle<T>) -> Self {
64 Self {
65 inner: Inner::Local(task),
66 }
67 }
68
69 pub(crate) fn remote(join: RemoteJoin<T>) -> Self {
70 Self {
71 inner: Inner::Remote(join),
72 }
73 }
74
75 pub fn cancel(self) {
77 match self.inner {
78 Inner::Local(t) => t.cancel(),
79 Inner::Remote(t) => t.cancel(),
80 }
81 }
82
83 pub fn detach(self) {}
85
86 pub fn is_finished(&self) -> bool {
88 match &self.inner {
89 Inner::Local(t) => t.is_finished(),
90 Inner::Remote(t) => t.is_finished(),
91 }
92 }
93}
94
95impl<T> Future for RemoteJoinHandle<T> {
96 type Output = Result<T, JoinError>;
97
98 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
99 Poll::Ready(match &mut self.inner {
100 Inner::Local(t) => ready!(Pin::new(t).poll(cx)),
101 Inner::Remote(t) => ready!(t.poll_join(cx)).ok_or(JoinError),
102 })
103 }
104}
105
106#[derive(Debug, Copy, Clone)]
108pub struct JoinError;
109
110impl fmt::Display for JoinError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "JoinError")
113 }
114}
115
116impl std::error::Error for JoinError {}
117
118#[cfg(all(test, not(feature = "tokio"), not(feature = "compio")))]
119mod tests {
120 use std::future::{pending, poll_fn};
121
122 use crate::{Handle, System, testing::TestRunner};
123
124 #[test]
125 fn join_handle() {
126 assert_eq!(size_of::<crate::JoinHandle<usize>>(), size_of::<usize>());
127 System::new("test", TestRunner).block_on(async {
128 let hnd = crate::spawn(pending::<()>());
129 assert!(!hnd.is_finished());
130 hnd.cancel();
131
132 assert_eq!(crate::spawn(async { 1 }).await.unwrap(), 1);
133
134 let hnd = crate::spawn(async {});
135 poll_fn(|cx| {
136 if hnd.is_finished() {
137 std::task::Poll::Ready(())
138 } else {
139 cx.waker().wake_by_ref();
140 std::task::Poll::Pending
141 }
142 })
143 .await;
144
145 let hnd = Handle::current().clone();
146 hnd.notify().unwrap();
147 });
148 assert_eq!(super::JoinError.to_string(), "JoinError");
149 assert_eq!(crate::rt_default::JoinError.to_string(), "JoinError");
150 }
151}