Skip to main content

qubit_dcl/double_checked/
execution_context.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 Context
11//!
12//! Provides execution context after double-checked lock task execution.
13//!
14use crate::double_checked::{
15    execution_result::ExecutionResult,
16    executor_error::ExecutorError,
17};
18
19/// Execution context (state after task execution)
20///
21/// This type provides result retrieval functionality after task execution.
22///
23/// Prepare lifecycle callbacks are configured on
24/// [`super::DoubleCheckedLockExecutor`] and are already applied before an
25/// `ExecutionContext` is returned. Task closures are responsible for their own
26/// rollback, cleanup, and commit logic.
27///
28/// # Type Parameters
29///
30/// * `T` - The type of the task return value
31/// * `E` - The type of the task error
32///
33pub struct ExecutionContext<T, E>
34where
35    E: std::fmt::Display,
36{
37    /// Result produced by the double-checked execution.
38    result: ExecutionResult<T, E>,
39}
40
41impl<T, E> ExecutionContext<T, E>
42where
43    E: std::fmt::Display,
44{
45    /// Creates a new execution context.
46    ///
47    /// # Parameters
48    ///
49    /// * `result` - The execution result
50    ///
51    /// # Returns
52    ///
53    /// A context wrapping the supplied result.
54    #[inline]
55    pub(super) fn new(result: ExecutionResult<T, E>) -> Self {
56        Self { result }
57    }
58
59    /// Gets the execution result (consumes the context)
60    ///
61    /// Prepare commit or rollback callbacks have already been executed by the
62    /// builder before this context was created. This method does not trigger
63    /// additional side effects.
64    ///
65    /// # Returns
66    ///
67    /// The owned [`ExecutionResult`] stored in this context.
68    #[inline]
69    pub fn get_result(self) -> ExecutionResult<T, E> {
70        self.result
71    }
72
73    /// Checks the execution result (does not consume the context)
74    ///
75    /// # Returns
76    ///
77    /// A shared reference to the stored [`ExecutionResult`].
78    #[inline]
79    pub fn peek_result(&self) -> &ExecutionResult<T, E> {
80        &self.result
81    }
82
83    /// Checks if execution was successful
84    ///
85    /// # Returns
86    ///
87    /// `true` if the stored result is [`ExecutionResult::Success`].
88    #[inline]
89    pub fn is_success(&self) -> bool {
90        self.result.is_success()
91    }
92}
93
94// Convenience methods for cases without return values
95impl<E> ExecutionContext<(), E>
96where
97    E: std::fmt::Display,
98{
99    /// Completes execution (for operations without return values)
100    ///
101    /// Returns whether the execution was successful. This convenience method
102    /// intentionally collapses both unmet conditions and execution failures to
103    /// `false`; use [`Self::try_finish`] when the failure details must be
104    /// preserved.
105    ///
106    /// # Returns
107    ///
108    /// `true` if the stored result is [`ExecutionResult::Success`] containing
109    /// `()`.
110    #[inline]
111    pub fn finish(self) -> bool {
112        let result = self.get_result();
113        result.is_success()
114    }
115
116    /// Completes execution while preserving failure details.
117    ///
118    /// # Returns
119    ///
120    /// * `Ok(true)` - Execution succeeded with `()`.
121    /// * `Ok(false)` - The double-checked condition was not met.
122    /// * `Err(ExecutorError<E>)` - Execution failed, preserving the original
123    ///   executor error.
124    ///
125    /// # Errors
126    ///
127    /// Returns the stored [`ExecutorError`] when the underlying result is
128    /// [`ExecutionResult::Failed`].
129    #[inline]
130    pub fn try_finish(self) -> Result<bool, ExecutorError<E>> {
131        match self.get_result() {
132            ExecutionResult::Success(()) => Ok(true),
133            ExecutionResult::ConditionNotMet => Ok(false),
134            ExecutionResult::Failed(error) => Err(error),
135        }
136    }
137}