Skip to main content

ntex_rt/
handle.rs

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
7/// The location a task was spawned at.
8pub(crate) type SpawnLocation = &'static Location<'static>;
9
10/// A local task handle. It is neither `Send` nor `Sync`.
11///
12/// Returned by [`crate::spawn()`] and [`crate::Runtime::spawn()`]. Dropping
13/// the handle detaches the task.
14#[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    /// Cancels the task.
25    pub fn cancel(self) {
26        self.task.cancel();
27    }
28
29    /// Detaches the task so it continues running independently.
30    pub fn detach(self) {}
31
32    /// Returns `true` if the task has finished.
33    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/// A task handle returned by [`crate::Handle::spawn()`].
47///
48/// It is neither `Send` nor `Sync` and stays on the calling thread.
49/// Submissions on the runtime thread retain the local spawn fast path.
50/// Dropping the handle detaches the task.
51#[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    /// Cancels the task, dropping its future on the runtime thread.
76    pub fn cancel(self) {
77        match self.inner {
78            Inner::Local(t) => t.cancel(),
79            Inner::Remote(t) => t.cancel(),
80        }
81    }
82
83    /// Detaches the task so it continues running independently.
84    pub fn detach(self) {}
85
86    /// Returns `true` if the task has finished.
87    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/// Error returned when a task handle no longer contains a task.
107#[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}