qubit_executor/task/tracked_task.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::future::IntoFuture;
11
12use super::{
13 TaskResult,
14 cancel_result::CancelResult,
15 task_handle::TaskHandle,
16 task_handle_future::TaskHandleFuture,
17 task_result_handle::TaskResultHandle,
18 task_status::TaskStatus,
19 tracked_task_handle::TrackedTaskHandle,
20 try_get::TryGet,
21};
22use crate::hook::TaskId;
23
24/// Result handle with active status tracking and pre-start cancellation.
25pub struct TrackedTask<R, E> {
26 /// Lightweight result handle.
27 handle: TaskHandle<R, E>,
28}
29
30impl<R, E> TrackedTask<R, E> {
31 /// Creates a tracked task from a result handle and completion state.
32 ///
33 /// # Parameters
34 ///
35 /// * `handle` - Result handle used to retrieve the final task result.
36 /// # Returns
37 ///
38 /// A tracked task handle.
39 #[inline]
40 pub(crate) const fn new(handle: TaskHandle<R, E>) -> Self {
41 Self { handle }
42 }
43
44 /// Waits for the task to finish and returns its final result.
45 ///
46 /// # Returns
47 ///
48 /// The final task result.
49 #[inline]
50 pub fn get(self) -> TaskResult<R, E>
51 where
52 R: Send,
53 E: Send,
54 {
55 <Self as TaskResultHandle<R, E>>::get(self)
56 }
57
58 /// Attempts to retrieve the final result without blocking.
59 ///
60 /// # Returns
61 ///
62 /// A ready result or the pending tracked handle.
63 #[inline]
64 pub fn try_get(self) -> TryGet<Self, R, E>
65 where
66 R: Send,
67 E: Send,
68 {
69 <Self as TaskResultHandle<R, E>>::try_get(self)
70 }
71
72 /// Returns whether the tracked task has installed a terminal state.
73 ///
74 /// # Returns
75 ///
76 /// `true` after the task succeeds, fails, panics, is cancelled, or loses
77 /// its completion endpoint. The final result send may still be racing with
78 /// this status observation.
79 #[inline]
80 pub fn is_done(&self) -> bool
81 where
82 R: Send,
83 E: Send,
84 {
85 <Self as TaskResultHandle<R, E>>::is_done(self)
86 }
87
88 /// Returns the currently observed task status.
89 ///
90 /// # Returns
91 ///
92 /// The current task status.
93 #[inline]
94 pub fn status(&self) -> TaskStatus {
95 self.handle.state.status()
96 }
97
98 /// Returns the identifier assigned to this task.
99 ///
100 /// # Returns
101 ///
102 /// The task id stored in the shared task state.
103 #[inline]
104 pub fn task_id(&self) -> TaskId {
105 self.handle.task_id()
106 }
107
108 /// Marks the task accepted and emits the accepted hook once.
109 #[inline]
110 pub(crate) fn accept(&self) {
111 self.handle.accept();
112 }
113
114 /// Attempts to cancel this task before it starts.
115 ///
116 /// # Returns
117 ///
118 /// The observed cancellation outcome.
119 #[inline]
120 pub fn cancel(&self) -> CancelResult {
121 self.cancel_inner()
122 }
123
124 /// Performs the shared cancellation state transition.
125 ///
126 /// # Returns
127 ///
128 /// The observed cancellation outcome.
129 #[inline]
130 fn cancel_inner(&self) -> CancelResult {
131 if self.handle.state.try_cancel_pending() {
132 return CancelResult::Cancelled;
133 }
134 match self.status() {
135 TaskStatus::Pending => CancelResult::Unsupported,
136 TaskStatus::Running => CancelResult::AlreadyRunning,
137 _ => CancelResult::AlreadyFinished,
138 }
139 }
140}
141
142impl<R, E> TaskResultHandle<R, E> for TrackedTask<R, E>
143where
144 R: Send,
145 E: Send,
146{
147 /// Returns whether the tracked state is terminal.
148 #[inline]
149 fn is_done(&self) -> bool {
150 self.status().is_done()
151 }
152
153 /// Blocks until the underlying result handle yields a result.
154 #[inline]
155 fn get(self) -> TaskResult<R, E> {
156 self.handle.get()
157 }
158
159 /// Attempts to retrieve the underlying result without blocking.
160 #[inline]
161 fn try_get(self) -> TryGet<Self, R, E> {
162 let Self { handle } = self;
163 match handle.try_get() {
164 TryGet::Ready(result) => TryGet::Ready(result),
165 TryGet::Pending(handle) => TryGet::Pending(Self { handle }),
166 }
167 }
168}
169
170impl<R, E> TrackedTaskHandle<R, E> for TrackedTask<R, E>
171where
172 R: Send,
173 E: Send,
174{
175 /// Returns the currently observed task status.
176 #[inline]
177 fn status(&self) -> TaskStatus {
178 self.handle.state.status()
179 }
180
181 /// Attempts to publish a cancellation result while the task is pending.
182 #[inline]
183 fn cancel(&self) -> CancelResult {
184 self.cancel_inner()
185 }
186}
187
188impl<R, E> IntoFuture for TrackedTask<R, E> {
189 type Output = TaskResult<R, E>;
190 type IntoFuture = TaskHandleFuture<R, E>;
191
192 /// Converts this tracked handle into a future resolving to the task result.
193 #[inline]
194 fn into_future(self) -> Self::IntoFuture {
195 self.handle.into_future()
196 }
197}