Skip to main content

qubit_executor/task/
task_handle.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9use std::{
10    future::Future,
11    pin::Pin,
12    sync::Arc,
13    task::{
14        Context,
15        Poll,
16    },
17};
18
19use super::TaskResult;
20use super::task_completion::TaskCompletion;
21use super::task_handle_inner::TaskHandleInner;
22
23/// Handle for a task running outside the caller's current stack.
24///
25/// `TaskHandle` is returned by thread-backed executors and services. Calling
26/// [`Self::get`] blocks the current thread until the accepted task completes.
27/// Awaiting the handle waits asynchronously for the same final task result.
28///
29/// # Type Parameters
30///
31/// * `R` - The task success value.
32/// * `E` - The task error value.
33///
34/// # Author
35///
36/// Haixing Hu
37pub struct TaskHandle<R, E> {
38    /// Shared state observed by the handle and updated by completion endpoints.
39    pub(crate) inner: Arc<TaskHandleInner<R, E>>,
40}
41
42impl<R, E> TaskHandle<R, E> {
43    /// Waits for the task to finish and returns its final result.
44    ///
45    /// This method blocks the current thread until a result is available.
46    ///
47    /// # Returns
48    ///
49    /// `Ok(R)` if the task succeeds. If the accepted task returns `Err(E)`,
50    /// panics, or is cancelled before producing a value, the corresponding
51    /// [`crate::TaskExecutionError`] is returned.
52    pub fn get(self) -> TaskResult<R, E> {
53        self.inner.state.wait_until(
54            |state| state.completed,
55            |state| {
56                state
57                    .result
58                    .take()
59                    .expect("task handle completed without a result")
60            },
61        )
62    }
63
64    /// Returns whether the task has reported completion.
65    ///
66    /// # Returns
67    ///
68    /// `true` after the task runner has produced or abandoned its final result.
69    #[inline]
70    pub fn is_done(&self) -> bool {
71        self.inner.done.load()
72    }
73
74    /// Attempts to cancel the task.
75    ///
76    /// Cancellation can only win before the runner marks the task as started.
77    /// It cannot interrupt a task that is already running on an OS thread.
78    ///
79    /// # Returns
80    ///
81    /// `true` if the task was cancelled before it started, or `false` if the
82    /// task was already running or completed.
83    #[inline]
84    pub fn cancel(&self) -> bool {
85        TaskCompletion {
86            inner: Arc::clone(&self.inner),
87        }
88        .cancel()
89    }
90}
91
92impl<R, E> Future for TaskHandle<R, E> {
93    type Output = TaskResult<R, E>;
94
95    /// Polls this handle for the accepted task's final result.
96    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
97        let result = self.inner.state.write(|state| {
98            if state.completed {
99                Some(
100                    state
101                        .result
102                        .take()
103                        .expect("task handle completed without a result"),
104                )
105            } else {
106                state.waker = Some(cx.waker().clone());
107                None
108            }
109        });
110        if let Some(result) = result {
111            Poll::Ready(result)
112        } else {
113            Poll::Pending
114        }
115    }
116}