Skip to main content

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}