Skip to main content

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}