Skip to main content

qubit_executor/schedule/
scheduled_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::IntoFuture,
12    sync::{
13        Arc,
14        atomic::{
15            AtomicBool,
16            Ordering,
17        },
18    },
19};
20
21use crate::{
22    CancelResult,
23    TaskResult,
24    TaskStatus,
25    TrackedTask,
26    TryGet,
27    hook::TaskId,
28    task::{
29        TaskHandleFuture,
30        spi::{
31            TaskResultHandle,
32            TrackedTaskHandle,
33        },
34    },
35};
36
37/// Tracked handle for a task accepted by a scheduled executor service.
38///
39/// The handle delegates result and status observation to the standard
40/// [`TrackedTask`] while also waking the scheduler when pre-start cancellation
41/// wins. This prevents a cancelled timer entry from keeping the single scheduler
42/// thread asleep until the original deadline.
43pub struct ScheduledTaskHandle<R, E> {
44    /// Standard tracked task handle.
45    inner: TrackedTask<R, E>,
46    /// Shared marker observed by the scheduler heap.
47    cancellation_marker: Arc<AtomicBool>,
48    /// Callback invoked after this handle cancels the pending task.
49    on_cancelled: Arc<dyn Fn() + Send + Sync + 'static>,
50}
51
52impl<R, E> ScheduledTaskHandle<R, E> {
53    /// Creates a scheduled task handle.
54    ///
55    /// # Parameters
56    ///
57    /// * `inner` - Standard tracked task handle.
58    /// * `cancellation_marker` - Shared marker observed by the scheduler heap.
59    /// * `on_cancelled` - Callback invoked when this handle cancels the task.
60    ///
61    /// # Returns
62    ///
63    /// A scheduled task handle.
64    pub(crate) const fn new(
65        inner: TrackedTask<R, E>,
66        cancellation_marker: Arc<AtomicBool>,
67        on_cancelled: Arc<dyn Fn() + Send + Sync + 'static>,
68    ) -> Self {
69        Self {
70            inner,
71            cancellation_marker,
72            on_cancelled,
73        }
74    }
75
76    /// Waits for the task to finish and returns its final result.
77    ///
78    /// # Returns
79    ///
80    /// The final task result.
81    #[inline]
82    pub fn get(self) -> TaskResult<R, E>
83    where
84        R: Send,
85        E: Send,
86    {
87        <Self as TaskResultHandle<R, E>>::get(self)
88    }
89
90    /// Attempts to retrieve the final result without blocking.
91    ///
92    /// # Returns
93    ///
94    /// A ready result or the pending scheduled handle.
95    #[inline]
96    pub fn try_get(self) -> TryGet<Self, R, E>
97    where
98        R: Send,
99        E: Send,
100    {
101        <Self as TaskResultHandle<R, E>>::try_get(self)
102    }
103
104    /// Returns whether the tracked task has installed a terminal state.
105    ///
106    /// # Returns
107    ///
108    /// `true` after the task succeeds, fails, panics, is cancelled, or loses its
109    /// completion endpoint.
110    #[inline]
111    pub fn is_done(&self) -> bool
112    where
113        R: Send,
114        E: Send,
115    {
116        <Self as TaskResultHandle<R, E>>::is_done(self)
117    }
118
119    /// Returns the currently observed task status.
120    ///
121    /// # Returns
122    ///
123    /// The current task status.
124    #[inline]
125    pub fn status(&self) -> TaskStatus {
126        self.inner.status()
127    }
128
129    /// Returns the identifier assigned to this task.
130    ///
131    /// # Returns
132    ///
133    /// The task id stored in the shared task state.
134    #[inline]
135    pub fn task_id(&self) -> TaskId {
136        self.inner.task_id()
137    }
138
139    /// Attempts to cancel this task before it starts.
140    ///
141    /// # Returns
142    ///
143    /// The observed cancellation outcome.
144    #[inline]
145    pub fn cancel(&self) -> CancelResult {
146        self.cancel_inner()
147    }
148
149    /// Performs cancellation and wakes the scheduler if this handle won.
150    ///
151    /// # Returns
152    ///
153    /// The observed cancellation outcome.
154    fn cancel_inner(&self) -> CancelResult {
155        let result = self.inner.cancel();
156        if result == CancelResult::Cancelled {
157            self.cancellation_marker.store(true, Ordering::Release);
158            (self.on_cancelled)();
159        }
160        result
161    }
162}
163
164impl<R, E> TaskResultHandle<R, E> for ScheduledTaskHandle<R, E>
165where
166    R: Send,
167    E: Send,
168{
169    /// Returns whether the tracked state is terminal.
170    #[inline]
171    fn is_done(&self) -> bool {
172        self.inner.is_done()
173    }
174
175    /// Blocks until the underlying result handle yields a result.
176    #[inline]
177    fn get(self) -> TaskResult<R, E> {
178        self.inner.get()
179    }
180
181    /// Attempts to retrieve the underlying result without blocking.
182    #[inline]
183    fn try_get(self) -> TryGet<Self, R, E> {
184        let Self {
185            inner,
186            cancellation_marker,
187            on_cancelled,
188        } = self;
189        match inner.try_get() {
190            TryGet::Ready(result) => TryGet::Ready(result),
191            TryGet::Pending(inner) => TryGet::Pending(Self {
192                inner,
193                cancellation_marker,
194                on_cancelled,
195            }),
196        }
197    }
198}
199
200impl<R, E> TrackedTaskHandle<R, E> for ScheduledTaskHandle<R, E>
201where
202    R: Send,
203    E: Send,
204{
205    /// Returns the currently observed task status.
206    #[inline]
207    fn status(&self) -> TaskStatus {
208        self.inner.status()
209    }
210
211    /// Attempts to publish a cancellation result while the task is pending.
212    #[inline]
213    fn cancel(&self) -> CancelResult {
214        self.cancel_inner()
215    }
216}
217
218impl<R, E> IntoFuture for ScheduledTaskHandle<R, E> {
219    type Output = TaskResult<R, E>;
220    type IntoFuture = TaskHandleFuture<R, E>;
221
222    /// Converts this scheduled handle into a future resolving to the task result.
223    #[inline]
224    fn into_future(self) -> Self::IntoFuture {
225        self.inner.into_future()
226    }
227}