Skip to main content

qubit_executor/task/
task_execution_error.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::error::Error;
11use std::fmt;
12
13/// Result type used by managed task handles.
14pub type TaskResult<R, E> = Result<R, TaskExecutionError<E>>;
15
16/// Error observed when retrieving the result of an accepted task.
17///
18/// This error is distinct from [`SubmissionError`](crate::SubmissionError).
19/// Rejection happens before a service accepts a task; `TaskExecutionError`
20/// describes what happened after the task was accepted.
21///
22/// # Type Parameters
23///
24/// * `E` - The error type returned by the task itself.
25///
26#[derive(Debug)]
27pub enum TaskExecutionError<E> {
28    /// The task ran and returned `Err(E)`.
29    Failed(E),
30
31    /// The task panicked while running.
32    Panicked,
33
34    /// The task was explicitly cancelled before producing a result.
35    ///
36    /// This includes caller-side cancellation through tracked handles and
37    /// executor/service-side cancellation of queued, scheduled, or otherwise
38    /// unstarted work.
39    Cancelled,
40
41    /// The accepted runner-side completion endpoint was abandoned without
42    /// publishing an explicit terminal result.
43    ///
44    /// This represents runner loss or misuse. Services that intentionally stop
45    /// unstarted accepted work should publish [`Self::Cancelled`] instead.
46    Dropped,
47}
48
49impl<E> TaskExecutionError<E> {
50    /// Returns true when this error wraps the task's own error value.
51    ///
52    /// # Returns
53    ///
54    /// `true` if the task returned `Err(E)`.
55    #[inline]
56    pub const fn is_failed(&self) -> bool {
57        matches!(self, Self::Failed(_))
58    }
59
60    /// Returns true when the task panicked.
61    ///
62    /// # Returns
63    ///
64    /// `true` if the task panicked while running.
65    #[inline]
66    pub const fn is_panicked(&self) -> bool {
67        matches!(self, Self::Panicked)
68    }
69
70    /// Returns true when the task was explicitly cancelled.
71    ///
72    /// # Returns
73    ///
74    /// `true` if the task was cancelled before producing a result.
75    #[inline]
76    pub const fn is_cancelled(&self) -> bool {
77        matches!(self, Self::Cancelled)
78    }
79
80    /// Returns true when the task result was abandoned by the completion endpoint.
81    ///
82    /// # Returns
83    ///
84    /// `true` if the accepted runner-side completion endpoint disappeared
85    /// without publishing an explicit terminal result.
86    #[inline]
87    pub const fn is_dropped(&self) -> bool {
88        matches!(self, Self::Dropped)
89    }
90}
91
92impl<E> fmt::Display for TaskExecutionError<E>
93where
94    E: fmt::Display,
95{
96    /// Formats this task execution error for users.
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        match self {
99            Self::Failed(err) => write!(f, "task failed: {err}"),
100            Self::Panicked => f.write_str("task panicked"),
101            Self::Cancelled => f.write_str("task was cancelled"),
102            Self::Dropped => f.write_str("task result was dropped"),
103        }
104    }
105}
106
107impl<E> Error for TaskExecutionError<E> where E: Error + 'static {}