Skip to main content

qubit_lock/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::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_lock::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>
51where
52    E: std::fmt::Display,
53{
54    /// Execution succeeded with a value
55    Success(T),
56
57    /// Double-checked locking condition was not met
58    ConditionNotMet,
59
60    /// Execution failed with an error
61    Failed(ExecutorError<E>),
62}
63
64impl<T, E> ExecutionResult<T, E>
65where
66    E: std::fmt::Display,
67{
68    /// Builds [`ExecutionResult::Success`] with `value`.
69    ///
70    /// # Parameters
71    ///
72    /// * `value` - Successful task value.
73    ///
74    /// # Returns
75    ///
76    /// A success result containing `value`.
77    #[inline]
78    pub fn success(value: T) -> Self {
79        ExecutionResult::Success(value)
80    }
81
82    /// Builds [`ExecutionResult::ConditionNotMet`].
83    ///
84    /// # Returns
85    ///
86    /// A result representing a failed double-check condition.
87    #[inline]
88    pub fn unmet() -> Self {
89        ExecutionResult::ConditionNotMet
90    }
91
92    /// Builds a failed result with [`ExecutorError::TaskFailed`].
93    ///
94    /// # Parameters
95    ///
96    /// * `err` - Error returned by the executed task.
97    ///
98    /// # Returns
99    ///
100    /// A failed result wrapping the task error.
101    #[inline]
102    pub fn task_failed(err: E) -> Self {
103        ExecutionResult::Failed(ExecutorError::TaskFailed(err))
104    }
105
106    /// Builds a failed result with [`ExecutorError::PrepareFailed`].
107    ///
108    /// Accepts any [`fmt::Display`] value (including [`std::error::Error`] and [`String`]);
109    /// the message is stored as a [`String`] via [`ToString`].
110    ///
111    /// # Parameters
112    ///
113    /// * `msg` - Prepare error message or displayable error value.
114    ///
115    /// # Returns
116    ///
117    /// A failed result containing the prepare failure message.
118    #[inline]
119    pub fn prepare_failed(msg: impl fmt::Display) -> Self {
120        ExecutionResult::Failed(ExecutorError::PrepareFailed(msg.to_string()))
121    }
122
123    /// Builds a failed result with [`ExecutorError::PrepareCommitFailed`].
124    ///
125    /// # Parameters
126    ///
127    /// * `msg` - Commit error message or displayable error value.
128    ///
129    /// # Returns
130    ///
131    /// A failed result containing the prepare-commit failure message.
132    #[inline]
133    pub fn prepare_commit_failed(msg: impl fmt::Display) -> Self {
134        ExecutionResult::Failed(ExecutorError::PrepareCommitFailed(msg.to_string()))
135    }
136
137    /// Builds a failed result with [`ExecutorError::PrepareRollbackFailed`].
138    ///
139    /// # Parameters
140    ///
141    /// * `original` - Original failure that triggered prepare rollback.
142    /// * `rollback` - Failure produced by the rollback action.
143    ///
144    /// # Returns
145    ///
146    /// A failed result containing both original and rollback messages.
147    #[inline]
148    pub fn prepare_rollback_failed(
149        original: impl Into<String>,
150        rollback: impl Into<String>,
151    ) -> Self {
152        ExecutionResult::Failed(ExecutorError::PrepareRollbackFailed {
153            original: original.into(),
154            rollback: rollback.into(),
155        })
156    }
157
158    /// Builds a failed result with [`ExecutorError::LockPoisoned`].
159    ///
160    /// # Parameters
161    ///
162    /// * `msg` - Lock poisoning diagnostic message.
163    ///
164    /// # Returns
165    ///
166    /// A failed result containing the lock poisoning message.
167    #[inline]
168    pub fn lock_poisoned(msg: impl Into<String>) -> Self {
169        ExecutionResult::Failed(ExecutorError::LockPoisoned(msg.into()))
170    }
171
172    /// Wraps an arbitrary [`ExecutorError`] as [`ExecutionResult::Failed`].
173    ///
174    /// # Parameters
175    ///
176    /// * `err` - Executor error to store in the failed result.
177    ///
178    /// # Returns
179    ///
180    /// A failed result containing `err`.
181    #[inline]
182    pub fn from_executor_error(err: ExecutorError<E>) -> Self {
183        ExecutionResult::Failed(err)
184    }
185
186    /// Checks if the execution was successful
187    ///
188    /// # Returns
189    ///
190    /// `true` if this result is [`ExecutionResult::Success`].
191    #[inline]
192    pub fn is_success(&self) -> bool {
193        matches!(self, ExecutionResult::Success(_))
194    }
195
196    /// Checks if the condition was not met
197    ///
198    /// # Returns
199    ///
200    /// `true` if this result is [`ExecutionResult::ConditionNotMet`].
201    #[inline]
202    pub fn is_unmet(&self) -> bool {
203        matches!(self, ExecutionResult::ConditionNotMet)
204    }
205
206    /// Checks if the execution failed
207    ///
208    /// # Returns
209    ///
210    /// `true` if this result is [`ExecutionResult::Failed`].
211    #[inline]
212    pub fn is_failed(&self) -> bool {
213        matches!(self, ExecutionResult::Failed(_))
214    }
215
216    /// Unwraps the success value, panicking if not successful
217    ///
218    /// # Returns
219    ///
220    /// The success value stored in [`ExecutionResult::Success`].
221    ///
222    /// # Panics
223    ///
224    /// Panics if this result is [`ExecutionResult::ConditionNotMet`] or
225    /// [`ExecutionResult::Failed`].
226    #[inline]
227    pub fn unwrap(self) -> T {
228        match self {
229            ExecutionResult::Success(v) => v,
230            ExecutionResult::ConditionNotMet => {
231                panic!("Called unwrap on ExecutionResult::ConditionNotMet")
232            }
233            ExecutionResult::Failed(e) => {
234                panic!("Called unwrap on ExecutionResult::Failed: {}", e)
235            }
236        }
237    }
238
239    /// Converts the result to a standard Result
240    ///
241    /// # Returns
242    ///
243    /// * `Ok(Some(T))` - If execution was successful
244    /// * `Ok(None)` - If condition was not met
245    /// * `Err(ExecutorError<E>)` - If execution failed
246    ///
247    /// # Errors
248    ///
249    /// Returns the stored [`ExecutorError`] when this value is
250    /// [`ExecutionResult::Failed`].
251    #[inline]
252    pub fn into_result(self) -> Result<Option<T>, ExecutorError<E>> {
253        match self {
254            ExecutionResult::Success(v) => Ok(Some(v)),
255            ExecutionResult::ConditionNotMet => Ok(None),
256            ExecutionResult::Failed(e) => Err(e),
257        }
258    }
259}