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