qubit_dcl/double_checked/execution_result.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Execution Result
10//!
11//! Provides the task execution result enum for double-checked locking.
12//!
13//! # Author
14//!
15//! Haixing Hu
16use std::fmt;
17
18use crate::double_checked::executor_error::{CallbackError, ExecutorError};
19
20/// Task execution result
21///
22/// Represents the result of executing a task using an enum to clearly distinguish
23/// between success, unmet conditions, and failure.
24///
25/// # Type Parameters
26///
27/// * `T` - The type of the return value when execution succeeds
28/// * `E` - The type of the error when execution fails
29///
30/// # Examples
31///
32/// ```rust
33/// use qubit_dcl::double_checked::{ExecutionResult, ExecutorError};
34///
35/// let success: ExecutionResult<i32, String> = ExecutionResult::success(42);
36/// if let ExecutionResult::Success(val) = success {
37/// println!("Value: {}", val);
38/// }
39///
40/// let unmet: ExecutionResult<i32, String> = ExecutionResult::unmet();
41///
42/// let failed: ExecutionResult<i32, String> =
43/// ExecutionResult::task_failed("Task failed".to_string());
44/// ```
45///
46/// # Author
47///
48/// Haixing Hu
49#[derive(Debug)]
50pub enum ExecutionResult<T, E> {
51 /// Execution succeeded with a value
52 Success(T),
53
54 /// Double-checked locking condition was not met
55 ConditionNotMet,
56
57 /// Execution failed with an error
58 Failed(ExecutorError<E>),
59}
60
61impl<T, E> ExecutionResult<T, E> {
62 /// Builds [`ExecutionResult::Success`] with `value`.
63 ///
64 /// # Parameters
65 ///
66 /// * `value` - Successful task value.
67 ///
68 /// # Returns
69 ///
70 /// A success result containing `value`.
71 #[inline]
72 pub fn success(value: T) -> Self {
73 ExecutionResult::Success(value)
74 }
75
76 /// Builds [`ExecutionResult::ConditionNotMet`].
77 ///
78 /// # Returns
79 ///
80 /// A result representing a failed double-check condition.
81 #[inline]
82 pub fn unmet() -> Self {
83 ExecutionResult::ConditionNotMet
84 }
85
86 /// Builds a failed result with [`ExecutorError::TaskFailed`].
87 ///
88 /// # Parameters
89 ///
90 /// * `err` - Error returned by the executed task.
91 ///
92 /// # Returns
93 ///
94 /// A failed result wrapping the task error.
95 #[inline]
96 pub fn task_failed(err: E) -> Self {
97 ExecutionResult::Failed(ExecutorError::TaskFailed(err))
98 }
99
100 /// Builds a failed result with [`ExecutorError::PrepareFailed`].
101 ///
102 /// Accepts any [`std::fmt::Display`] value (including [`std::error::Error`] and [`String`]);
103 /// the message is stored in a [`CallbackError`] wrapper.
104 ///
105 /// # Parameters
106 ///
107 /// * `msg` - Prepare error message or displayable error value.
108 ///
109 /// # Returns
110 ///
111 /// A failed result containing the prepare failure message.
112 #[inline]
113 pub fn prepare_failed(msg: impl fmt::Display) -> Self {
114 ExecutionResult::Failed(ExecutorError::PrepareFailed(CallbackError::from_display(
115 msg,
116 )))
117 }
118
119 /// Builds a failed result with [`ExecutorError::PrepareCommitFailed`].
120 ///
121 /// # Parameters
122 ///
123 /// * `msg` - Commit error message or displayable error value.
124 ///
125 /// # Returns
126 ///
127 /// A failed result containing the prepare-commit failure message.
128 #[inline]
129 pub fn prepare_commit_failed(msg: impl fmt::Display) -> Self {
130 ExecutionResult::Failed(ExecutorError::PrepareCommitFailed(
131 CallbackError::from_display(msg),
132 ))
133 }
134
135 /// Builds a failed result with [`ExecutorError::PrepareFailed`] and explicit
136 /// callback type metadata.
137 ///
138 /// The callback type can later be read from
139 /// [`ExecutorError::callback_type`].
140 ///
141 /// # Parameters
142 ///
143 /// * `callback_type` - Callback type tag, e.g. `"prepare"`.
144 /// * `msg` - Failure message.
145 #[inline]
146 pub fn prepare_failed_with_type(
147 callback_type: &'static str,
148 msg: impl std::fmt::Display,
149 ) -> Self {
150 ExecutionResult::Failed(ExecutorError::PrepareFailed(CallbackError::with_type(
151 callback_type,
152 msg,
153 )))
154 }
155
156 /// Builds a failed result with [`ExecutorError::PrepareRollbackFailed`].
157 ///
158 /// # Parameters
159 ///
160 /// * `original` - Original failure that triggered prepare rollback.
161 /// * `rollback` - Failure produced by the rollback action.
162 ///
163 /// # Returns
164 ///
165 /// A failed result containing both original and rollback messages.
166 #[inline]
167 pub fn prepare_rollback_failed(
168 original: impl Into<String>,
169 rollback: impl Into<String>,
170 ) -> Self {
171 ExecutionResult::Failed(ExecutorError::PrepareRollbackFailed {
172 original: CallbackError::from_display(original.into()),
173 rollback: CallbackError::from_display(rollback.into()),
174 })
175 }
176
177 /// Wraps an arbitrary [`ExecutorError`] as [`ExecutionResult::Failed`].
178 ///
179 /// # Parameters
180 ///
181 /// * `err` - Executor error to store in the failed result.
182 ///
183 /// # Returns
184 ///
185 /// A failed result containing `err`.
186 #[inline]
187 pub fn from_executor_error(err: ExecutorError<E>) -> Self {
188 ExecutionResult::Failed(err)
189 }
190
191 /// Checks if the execution was successful.
192 ///
193 /// # Returns
194 ///
195 /// `true` if this result is [`ExecutionResult::Success`].
196 #[inline]
197 pub fn is_success(&self) -> bool {
198 matches!(self, ExecutionResult::Success(_))
199 }
200
201 /// Checks if the condition was not met.
202 ///
203 /// # Returns
204 ///
205 /// `true` if this result is [`ExecutionResult::ConditionNotMet`].
206 #[inline]
207 pub fn is_unmet(&self) -> bool {
208 matches!(self, ExecutionResult::ConditionNotMet)
209 }
210
211 /// Checks if the execution failed.
212 ///
213 /// # Returns
214 ///
215 /// `true` if this result is [`ExecutionResult::Failed`].
216 #[inline]
217 pub fn is_failed(&self) -> bool {
218 matches!(self, ExecutionResult::Failed(_))
219 }
220
221 /// Converts the result to a standard Result
222 ///
223 /// # Returns
224 ///
225 /// * `Ok(Some(T))` - If execution was successful
226 /// * `Ok(None)` - If condition was not met
227 /// * `Err(ExecutorError<E>)` - If execution failed
228 ///
229 /// # Errors
230 ///
231 /// Returns the stored [`ExecutorError`] when this value is
232 /// [`ExecutionResult::Failed`].
233 #[inline]
234 pub fn into_result(self) -> Result<Option<T>, ExecutorError<E>> {
235 match self {
236 ExecutionResult::Success(v) => Ok(Some(v)),
237 ExecutionResult::ConditionNotMet => Ok(None),
238 ExecutionResult::Failed(e) => Err(e),
239 }
240 }
241}
242
243impl<T, E> ExecutionResult<T, E>
244where
245 E: fmt::Display,
246{
247 /// Unwraps the success value, panicking if not successful
248 ///
249 /// # Returns
250 ///
251 /// The success value stored in [`ExecutionResult::Success`].
252 ///
253 /// # Panics
254 ///
255 /// Panics if this result is [`ExecutionResult::ConditionNotMet`] or
256 /// [`ExecutionResult::Failed`].
257 #[inline]
258 pub fn unwrap(self) -> T {
259 match self {
260 ExecutionResult::Success(v) => v,
261 ExecutionResult::ConditionNotMet => {
262 panic!("Called unwrap on ExecutionResult::ConditionNotMet")
263 }
264 ExecutionResult::Failed(e) => {
265 panic!("Called unwrap on ExecutionResult::Failed: {}", e)
266 }
267 }
268 }
269}