qubit_dcl/double_checked/executor_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 ******************************************************************************/
10//! # Executor Error
11//!
12//! Provides executor error types for the double-checked lock executor.
13//!
14
15use std::error::Error;
16use std::fmt;
17
18use super::CallbackError;
19
20/// Executor error types.
21///
22/// # Type Parameters
23///
24/// * `E` - The original error type from task execution
25///
26/// # Examples
27///
28/// ```rust
29/// use qubit_dcl::double_checked::ExecutorError;
30/// use qubit_dcl::double_checked::CallbackError;
31///
32/// let error: ExecutorError<String> =
33/// ExecutorError::TaskFailed("task failed".to_string());
34/// println!("Error: {}", error);
35///
36/// let error_with_msg: ExecutorError<String> =
37/// ExecutorError::PrepareFailed(CallbackError::from_display("Service is not running"));
38/// println!("Error: {}", error_with_msg);
39/// ```
40///
41///
42#[derive(Debug)]
43pub enum ExecutorError<E> {
44 /// Task execution failed with original error
45 TaskFailed(E),
46
47 /// Task execution panicked.
48 Panic(CallbackError),
49
50 /// Preparation action failed
51 PrepareFailed(CallbackError),
52
53 /// Commit action for a successfully completed prepare action failed.
54 PrepareCommitFailed(CallbackError),
55
56 /// Rollback action for a successfully completed prepare action failed.
57 PrepareRollbackFailed {
58 /// The original error that triggered the rollback
59 original: CallbackError,
60 /// The error that occurred during prepare rollback
61 rollback: CallbackError,
62 },
63}
64
65impl<E> fmt::Display for ExecutorError<E>
66where
67 E: fmt::Display,
68{
69 /// Formats this executor error for user-facing diagnostics.
70 ///
71 /// # Parameters
72 ///
73 /// * `f` - Formatter receiving the human-readable error text.
74 ///
75 /// # Returns
76 ///
77 /// [`fmt::Result`] from writing the formatted error text.
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 match self {
80 ExecutorError::TaskFailed(e) => {
81 write!(f, "Task execution failed: {}", e)
82 }
83 ExecutorError::Panic(error) => {
84 write!(f, "Execution panicked: {}", error)
85 }
86 ExecutorError::PrepareFailed(msg) => {
87 write!(f, "Preparation action failed: {}", msg)
88 }
89 ExecutorError::PrepareCommitFailed(msg) => {
90 write!(f, "Prepare commit action failed: {}", msg)
91 }
92 #[rustfmt::skip]
93 ExecutorError::PrepareRollbackFailed { original, rollback } => write!(f, "Prepare rollback failed: original error = {original}, rollback error = {rollback}"),
94 }
95 }
96}
97
98impl<E> ExecutorError<E> {
99 /// Returns the callback type label, when the error comes from a callback and
100 /// the type is available.
101 ///
102 /// This returns `None` for task failures and callback errors without
103 /// associated type labels.
104 #[inline]
105 pub fn callback_type(&self) -> Option<&'static str> {
106 match self {
107 ExecutorError::TaskFailed(_) => None,
108 ExecutorError::Panic(error) => error.callback_type(),
109 ExecutorError::PrepareFailed(error) => error.callback_type(),
110 ExecutorError::PrepareCommitFailed(error) => error.callback_type(),
111 ExecutorError::PrepareRollbackFailed { original, rollback } => {
112 rollback.callback_type().or(original.callback_type())
113 }
114 }
115 }
116}
117
118impl<E> Error for ExecutorError<E>
119where
120 E: Error + 'static,
121{
122 /// Returns the underlying task error as the standard error source.
123 ///
124 /// Prepare lifecycle failures store their messages as strings and therefore
125 /// do not expose a structured source error.
126 fn source(&self) -> Option<&(dyn Error + 'static)> {
127 match self {
128 ExecutorError::TaskFailed(error) => Some(error),
129 ExecutorError::Panic(_) => None,
130 ExecutorError::PrepareFailed(_) => None,
131 ExecutorError::PrepareCommitFailed(_) => None,
132 ExecutorError::PrepareRollbackFailed { .. } => None,
133 }
134 }
135}