Skip to main content

qubit_executor/task/
task_handle.rs

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