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}