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(msg)))
113 }
114
115 /// Builds a failed result with [`ExecutorError::PrepareCommitFailed`].
116 ///
117 /// # Parameters
118 ///
119 /// * `msg` - Commit error message or displayable error value.
120 ///
121 /// # Returns
122 ///
123 /// A failed result containing the prepare-commit failure message.
124 #[inline]
125 pub fn prepare_commit_failed(msg: impl fmt::Display) -> Self {
126 ExecutionResult::Failed(ExecutorError::PrepareCommitFailed(CallbackError::from_display(msg)))
127 }
128
129 /// Builds a failed result with [`ExecutorError::PrepareCommitFailed`] and
130 /// explicit callback type metadata.
131 ///
132 /// The callback type can later be read from
133 /// [`ExecutorError::callback_type`].
134 ///
135 /// # Parameters
136 ///
137 /// * `callback_type` - Callback type tag, e.g. `"prepare_commit"`.
138 /// * `msg` - Commit error message or displayable error value.
139 ///
140 /// # Returns
141 ///
142 /// A failed result containing the typed prepare-commit failure message.
143 #[inline]
144 pub fn prepare_commit_failed_with_callback_type(callback_type: &'static str, msg: impl fmt::Display) -> Self {
145 ExecutionResult::Failed(ExecutorError::PrepareCommitFailed(CallbackError::with_callback_type(
146 callback_type,
147 msg,
148 )))
149 }
150
151 /// Builds a failed result with [`ExecutorError::PrepareFailed`] and explicit
152 /// callback type metadata.
153 ///
154 /// The callback type can later be read from
155 /// [`ExecutorError::callback_type`].
156 ///
157 /// # Parameters
158 ///
159 /// * `callback_type` - Callback type tag, e.g. `"prepare"`.
160 /// * `msg` - Failure message.
161 ///
162 /// # Returns
163 ///
164 /// A failed result containing the typed prepare failure message.
165 #[inline]
166 pub fn prepare_failed_with_callback_type(callback_type: &'static str, msg: impl fmt::Display) -> Self {
167 ExecutionResult::Failed(ExecutorError::PrepareFailed(CallbackError::with_callback_type(
168 callback_type,
169 msg,
170 )))
171 }
172
173 /// Builds a failed result with [`ExecutorError::PrepareRollbackFailed`].
174 ///
175 /// # Parameters
176 ///
177 /// * `original` - Original failure that triggered prepare rollback.
178 /// * `rollback` - Failure produced by the rollback action.
179 ///
180 /// # Returns
181 ///
182 /// A failed result containing both original and rollback messages.
183 #[inline]
184 pub fn prepare_rollback_failed(original: impl fmt::Display, rollback: impl fmt::Display) -> Self {
185 ExecutionResult::Failed(ExecutorError::PrepareRollbackFailed {
186 original: CallbackError::from_display(original),
187 rollback: CallbackError::from_display(rollback),
188 })
189 }
190
191 /// Builds a failed result with [`ExecutorError::PrepareRollbackFailed`] and
192 /// explicit callback type metadata for the rollback action.
193 ///
194 /// The rollback callback type can later be read from
195 /// [`ExecutorError::callback_type`].
196 ///
197 /// # Parameters
198 ///
199 /// * `rollback_callback_type` - Callback type tag, e.g.
200 /// `"prepare_rollback"`.
201 /// * `original` - Original failure that triggered prepare rollback.
202 /// * `rollback` - Failure produced by the rollback action.
203 ///
204 /// # Returns
205 ///
206 /// A failed result containing both original and typed rollback messages.
207 #[inline]
208 pub fn prepare_rollback_failed_with_callback_type(
209 rollback_callback_type: &'static str,
210 original: impl fmt::Display,
211 rollback: impl fmt::Display,
212 ) -> Self {
213 ExecutionResult::Failed(ExecutorError::PrepareRollbackFailed {
214 original: CallbackError::from_display(original),
215 rollback: CallbackError::with_callback_type(rollback_callback_type, rollback),
216 })
217 }
218
219 /// Wraps an arbitrary [`ExecutorError`] as [`ExecutionResult::Failed`].
220 ///
221 /// # Parameters
222 ///
223 /// * `err` - Executor error to store in the failed result.
224 ///
225 /// # Returns
226 ///
227 /// A failed result containing `err`.
228 #[inline]
229 pub fn from_executor_error(err: ExecutorError<E>) -> Self {
230 ExecutionResult::Failed(err)
231 }
232
233 /// Checks if the execution was successful.
234 ///
235 /// # Returns
236 ///
237 /// `true` if this result is [`ExecutionResult::Success`].
238 #[inline]
239 pub fn is_success(&self) -> bool {
240 matches!(self, ExecutionResult::Success(_))
241 }
242
243 /// Checks if the condition was not met.
244 ///
245 /// # Returns
246 ///
247 /// `true` if this result is [`ExecutionResult::ConditionNotMet`].
248 #[inline]
249 pub fn is_unmet(&self) -> bool {
250 matches!(self, ExecutionResult::ConditionNotMet)
251 }
252
253 /// Checks if the execution failed.
254 ///
255 /// # Returns
256 ///
257 /// `true` if this result is [`ExecutionResult::Failed`].
258 #[inline]
259 pub fn is_failed(&self) -> bool {
260 matches!(self, ExecutionResult::Failed(_))
261 }
262
263 /// Converts the result to a standard Result
264 ///
265 /// # Returns
266 ///
267 /// * `Ok(Some(T))` - If execution was successful
268 /// * `Ok(None)` - If condition was not met
269 /// * `Err(ExecutorError<E>)` - If execution failed
270 ///
271 /// # Errors
272 ///
273 /// Returns the stored [`ExecutorError`] when this value is
274 /// [`ExecutionResult::Failed`].
275 #[inline]
276 pub fn into_result(self) -> Result<Option<T>, ExecutorError<E>> {
277 match self {
278 ExecutionResult::Success(v) => Ok(Some(v)),
279 ExecutionResult::ConditionNotMet => Ok(None),
280 ExecutionResult::Failed(e) => Err(e),
281 }
282 }
283}
284
285impl<T, E> ExecutionResult<T, E>
286where
287 E: fmt::Display,
288{
289 /// Unwraps the success value, panicking if not successful
290 ///
291 /// # Returns
292 ///
293 /// The success value stored in [`ExecutionResult::Success`].
294 ///
295 /// # Panics
296 ///
297 /// Panics if this result is [`ExecutionResult::ConditionNotMet`] or
298 /// [`ExecutionResult::Failed`].
299 #[inline]
300 pub fn unwrap(self) -> T {
301 match self {
302 ExecutionResult::Success(v) => v,
303 ExecutionResult::ConditionNotMet => {
304 panic!("Called unwrap on ExecutionResult::ConditionNotMet")
305 }
306 ExecutionResult::Failed(e) => {
307 panic!("Called unwrap on ExecutionResult::Failed: {}", e)
308 }
309 }
310 }
311}