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}