Skip to main content

qubit_dcl/double_checked/
executor_ready_builder.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! Ready builder for [`super::DoubleCheckedLockExecutor`] (tester set, optional
10//! prepare hooks).
11//!
12//! # Author
13//!
14//! Haixing Hu
15
16use std::{fmt::Display, marker::PhantomData};
17
18use qubit_function::{ArcRunnable, ArcTester, Runnable};
19
20use super::executor_error::CallbackError;
21use super::{ExecutionLogger, double_checked_lock_executor::DoubleCheckedLockExecutor};
22use crate::lock::Lock;
23
24/// Builder state after the required condition tester has been configured.
25///
26/// This state can configure prepare lifecycle callbacks and build the final
27/// [`DoubleCheckedLockExecutor`].
28///
29/// # Type Parameters
30///
31/// * `L` - The lock type implementing [`Lock<T>`].
32/// * `T` - The data type protected by the lock.
33///
34/// # Author
35///
36/// Haixing Hu
37#[derive(Clone)]
38pub struct ExecutorReadyBuilder<L, T> {
39    /// The lock to store in the executor.
40    pub(in crate::double_checked) lock: L,
41
42    /// Required condition tester.
43    pub(in crate::double_checked) tester: ArcTester,
44
45    /// Logger used by the executor.
46    pub(in crate::double_checked) logger: ExecutionLogger,
47
48    /// Optional action executed after the first check and before locking.
49    pub(in crate::double_checked) prepare_action: Option<ArcRunnable<CallbackError>>,
50
51    /// Optional action executed when prepare must be rolled back.
52    pub(in crate::double_checked) rollback_prepare_action: Option<ArcRunnable<CallbackError>>,
53
54    /// Optional action executed when prepare should be committed.
55    pub(in crate::double_checked) commit_prepare_action: Option<ArcRunnable<CallbackError>>,
56
57    /// Whether panics from tester, callbacks, and task are converted to errors.
58    pub(in crate::double_checked) catch_panics: bool,
59
60    /// Carries the protected data type.
61    pub(in crate::double_checked) _phantom: PhantomData<fn() -> T>,
62}
63
64impl<L, T> ExecutorReadyBuilder<L, T>
65where
66    L: Lock<T>,
67{
68    /// Configures logging when the double-checked condition is not met.
69    #[inline]
70    pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
71        self.logger.set_unmet_condition(Some(level), message);
72        self
73    }
74
75    /// Disables logging when the double-checked condition is not met.
76    #[inline]
77    pub fn disable_unmet_condition_logging(mut self) -> Self {
78        self.logger.disable_unmet_condition();
79        self
80    }
81
82    /// Configures logging when the prepare action fails.
83    #[inline]
84    pub fn log_prepare_failure(
85        mut self,
86        level: log::Level,
87        message_prefix: impl Into<String>,
88    ) -> Self {
89        self.logger.set_prepare_failure(Some(level), message_prefix);
90        self
91    }
92
93    /// Disables logging when the prepare action fails.
94    #[inline]
95    pub fn disable_prepare_failure_logging(mut self) -> Self {
96        self.logger.disable_prepare_failure();
97        self
98    }
99
100    /// Configures logging when the prepare commit action fails.
101    #[inline]
102    pub fn log_prepare_commit_failure(
103        mut self,
104        level: log::Level,
105        message_prefix: impl Into<String>,
106    ) -> Self {
107        self.logger
108            .set_prepare_commit_failure(Some(level), message_prefix);
109        self
110    }
111
112    /// Disables logging when the prepare commit action fails.
113    #[inline]
114    pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
115        self.logger.disable_prepare_commit_failure();
116        self
117    }
118
119    /// Configures logging when the prepare rollback action fails.
120    #[inline]
121    pub fn log_prepare_rollback_failure(
122        mut self,
123        level: log::Level,
124        message_prefix: impl Into<String>,
125    ) -> Self {
126        self.logger
127            .set_prepare_rollback_failure(Some(level), message_prefix);
128        self
129    }
130
131    /// Disables logging when the prepare rollback action fails.
132    #[inline]
133    pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
134        self.logger.disable_prepare_rollback_failure();
135        self
136    }
137
138    /// Sets the prepare action.
139    ///
140    /// The action runs after the first condition check succeeds and before the
141    /// lock is acquired. If it succeeds, the executor will later run either
142    /// rollback or commit according to the final task result.
143    ///
144    /// Errors returned by this action are converted to [`String`] and reported
145    /// by execution methods as [`super::ExecutionResult::Failed`].
146    ///
147    /// # Parameters
148    ///
149    /// * `prepare_action` - The fallible action to run before locking.
150    ///
151    /// # Returns
152    ///
153    /// This builder with prepare configured.
154    #[inline]
155    pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
156    where
157        Rn: Runnable<E> + Send + 'static,
158        E: Display,
159    {
160        let mut action = prepare_action;
161        self.prepare_action = Some(ArcRunnable::new(move || {
162            action
163                .run()
164                .map_err(|error| CallbackError::with_type("prepare", error))
165        }));
166        self
167    }
168
169    /// Sets the rollback action for a successfully completed prepare action.
170    ///
171    /// Errors returned by this action are converted to [`String`] and replace
172    /// the original execution result with a prepare-rollback failure.
173    ///
174    /// # Parameters
175    ///
176    /// * `rollback_prepare_action` - The action to run if the second condition
177    ///   check or task execution fails after prepare succeeds.
178    ///
179    /// # Returns
180    ///
181    /// This builder with prepare rollback configured.
182    #[inline]
183    pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
184    where
185        Rn: Runnable<E> + Send + 'static,
186        E: Display,
187    {
188        let mut action = rollback_prepare_action;
189        self.rollback_prepare_action = Some(ArcRunnable::new(move || {
190            action
191                .run()
192                .map_err(|error| CallbackError::with_type("prepare_rollback", error))
193        }));
194        self
195    }
196
197    /// Sets the commit action for a successfully completed prepare action.
198    ///
199    /// Errors returned by this action are converted to [`String`] and replace
200    /// an otherwise successful execution result with a prepare-commit failure.
201    ///
202    /// # Parameters
203    ///
204    /// * `commit_prepare_action` - The action to run if the task succeeds after
205    ///   prepare succeeds.
206    ///
207    /// # Returns
208    ///
209    /// This builder with prepare commit configured.
210    #[inline]
211    pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
212    where
213        Rn: Runnable<E> + Send + 'static,
214        E: Display,
215    {
216        let mut action = commit_prepare_action;
217        self.commit_prepare_action = Some(ArcRunnable::new(move || {
218            action
219                .run()
220                .map_err(|error| CallbackError::with_type("prepare_commit", error))
221        }));
222        self
223    }
224
225    /// Enables panic capture for tester, prepare callbacks, and task execution.
226    ///
227    /// When enabled, panic payloads are converted to
228    /// [`super::executor_error::ExecutorError::Panic`] and surfaced through
229    /// [`super::ExecutionResult`].
230    #[inline]
231    pub fn catch_panics(mut self) -> Self {
232        self.catch_panics = true;
233        self
234    }
235
236    /// Sets whether panic capture for tester, prepare callbacks, and task
237    /// execution is enabled.
238    #[inline]
239    pub fn set_catch_panics(mut self, catch_panics: bool) -> Self {
240        self.catch_panics = catch_panics;
241        self
242    }
243
244    /// Disables panic capture for tester, prepare callbacks, and task execution.
245    #[inline]
246    pub fn disable_catch_panics(mut self) -> Self {
247        self.catch_panics = false;
248        self
249    }
250
251    /// Builds the reusable executor.
252    ///
253    /// # Returns
254    ///
255    /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
256    /// execution logger, and prepare lifecycle callbacks.
257    #[inline]
258    pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
259        DoubleCheckedLockExecutor::new(self)
260    }
261}