Skip to main content

qubit_dcl/double_checked/
executor_ready_builder.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//! Ready builder for [`super::DoubleCheckedLockExecutor`] (tester set, optional
11//! prepare hooks).
12//!
13
14use std::{
15    fmt::Display,
16    marker::PhantomData,
17};
18
19use qubit_function::{
20    ArcRunnable,
21    ArcTester,
22    Runnable,
23};
24
25use super::{
26    CallbackError,
27    ExecutionLogger,
28    double_checked_lock_executor::DoubleCheckedLockExecutor,
29};
30use crate::lock::Lock;
31
32/// Builder state after the required condition tester has been configured.
33///
34/// This state can configure prepare lifecycle callbacks and build the final
35/// [`DoubleCheckedLockExecutor`].
36///
37/// # Type Parameters
38///
39/// * `L` - The lock type implementing [`Lock<T>`].
40/// * `T` - The data type protected by the lock.
41///
42#[derive(Clone)]
43pub struct ExecutorReadyBuilder<L, T> {
44    /// The lock to store in the executor.
45    pub(in crate::double_checked) lock: L,
46
47    /// Required condition tester.
48    pub(in crate::double_checked) tester: ArcTester,
49
50    /// Logger used by the executor.
51    pub(in crate::double_checked) logger: ExecutionLogger,
52
53    /// Optional action executed after the first check and before locking.
54    pub(in crate::double_checked) prepare_action: Option<ArcRunnable<CallbackError>>,
55
56    /// Optional action executed when prepare must be rolled back.
57    pub(in crate::double_checked) rollback_prepare_action: Option<ArcRunnable<CallbackError>>,
58
59    /// Optional action executed when prepare should be committed.
60    pub(in crate::double_checked) commit_prepare_action: Option<ArcRunnable<CallbackError>>,
61
62    /// Whether panics from tester, callbacks, and task are converted to errors.
63    pub(in crate::double_checked) catch_panics: bool,
64
65    /// Carries the protected data type.
66    pub(in crate::double_checked) _phantom: PhantomData<fn() -> T>,
67}
68
69impl<L, T> ExecutorReadyBuilder<L, T>
70where
71    L: Lock<T>,
72{
73    /// Configures logging when the double-checked condition is not met.
74    ///
75    /// # Parameters
76    ///
77    /// * `level` - Log level used for unmet-condition messages.
78    /// * `message` - Full log message emitted when the condition is not met.
79    ///
80    /// # Returns
81    ///
82    /// This builder with unmet-condition logging configured.
83    #[inline]
84    #[must_use = "assign or chain the returned builder"]
85    pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
86        self.logger.set_unmet_condition(Some(level), message);
87        self
88    }
89
90    /// Disables logging when the double-checked condition is not met.
91    ///
92    /// # Returns
93    ///
94    /// This builder with unmet-condition logging disabled.
95    #[inline]
96    #[must_use = "assign or chain the returned builder"]
97    pub fn disable_unmet_condition_logging(mut self) -> Self {
98        self.logger.disable_unmet_condition();
99        self
100    }
101
102    /// Configures logging when the prepare action fails.
103    ///
104    /// # Parameters
105    ///
106    /// * `level` - Log level used for prepare failure messages.
107    /// * `message_prefix` - Prefix placed before the prepare failure text.
108    ///
109    /// # Returns
110    ///
111    /// This builder with prepare failure logging configured.
112    #[inline]
113    #[must_use = "assign or chain the returned builder"]
114    pub fn log_prepare_failure(
115        mut self,
116        level: log::Level,
117        message_prefix: impl Into<String>,
118    ) -> Self {
119        self.logger.set_prepare_failure(Some(level), message_prefix);
120        self
121    }
122
123    /// Disables logging when the prepare action fails.
124    ///
125    /// # Returns
126    ///
127    /// This builder with prepare failure logging disabled.
128    #[inline]
129    #[must_use = "assign or chain the returned builder"]
130    pub fn disable_prepare_failure_logging(mut self) -> Self {
131        self.logger.disable_prepare_failure();
132        self
133    }
134
135    /// Configures logging when the prepare commit action fails.
136    ///
137    /// # Parameters
138    ///
139    /// * `level` - Log level used for prepare-commit failure messages.
140    /// * `message_prefix` - Prefix placed before the prepare-commit failure
141    ///   text.
142    ///
143    /// # Returns
144    ///
145    /// This builder with prepare-commit failure logging configured.
146    #[inline]
147    #[must_use = "assign or chain the returned builder"]
148    pub fn log_prepare_commit_failure(
149        mut self,
150        level: log::Level,
151        message_prefix: impl Into<String>,
152    ) -> Self {
153        self.logger
154            .set_prepare_commit_failure(Some(level), message_prefix);
155        self
156    }
157
158    /// Disables logging when the prepare commit action fails.
159    ///
160    /// # Returns
161    ///
162    /// This builder with prepare-commit failure logging disabled.
163    #[inline]
164    #[must_use = "assign or chain the returned builder"]
165    pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
166        self.logger.disable_prepare_commit_failure();
167        self
168    }
169
170    /// Configures logging when the prepare rollback action fails.
171    ///
172    /// # Parameters
173    ///
174    /// * `level` - Log level used for prepare-rollback failure messages.
175    /// * `message_prefix` - Prefix placed before the prepare-rollback failure
176    ///   text.
177    ///
178    /// # Returns
179    ///
180    /// This builder with prepare-rollback failure logging configured.
181    #[inline]
182    #[must_use = "assign or chain the returned builder"]
183    pub fn log_prepare_rollback_failure(
184        mut self,
185        level: log::Level,
186        message_prefix: impl Into<String>,
187    ) -> Self {
188        self.logger
189            .set_prepare_rollback_failure(Some(level), message_prefix);
190        self
191    }
192
193    /// Disables logging when the prepare rollback action fails.
194    ///
195    /// # Returns
196    ///
197    /// This builder with prepare-rollback failure logging disabled.
198    #[inline]
199    #[must_use = "assign or chain the returned builder"]
200    pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
201        self.logger.disable_prepare_rollback_failure();
202        self
203    }
204
205    /// Sets the prepare action.
206    ///
207    /// The action runs after the first condition check succeeds and before the
208    /// lock is acquired. If it succeeds, the executor will later run either
209    /// rollback or commit according to the final task result.
210    ///
211    /// Errors returned by this action are converted to [`String`] and reported
212    /// by execution methods as [`super::ExecutionResult::Failed`].
213    ///
214    /// # Parameters
215    ///
216    /// * `prepare_action` - The fallible action to run before locking.
217    ///
218    /// # Returns
219    ///
220    /// This builder with prepare configured.
221    ///
222    /// # Errors
223    ///
224    /// This builder method does not return errors. If `prepare_action` later
225    /// returns an error during execution, the execution result becomes
226    /// [`super::ExecutionResult::Failed`] with
227    /// [`super::ExecutorError::PrepareFailed`].
228    #[inline]
229    #[must_use = "assign or chain the returned builder"]
230    pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
231    where
232        Rn: Runnable<E> + Send + 'static,
233        E: Display,
234    {
235        let mut action = prepare_action;
236        self.prepare_action = Some(ArcRunnable::new(move || {
237            action
238                .run()
239                .map_err(|error| CallbackError::with_callback_type("prepare", error))
240        }));
241        self
242    }
243
244    /// Sets the rollback action for a successfully completed prepare action.
245    ///
246    /// Errors returned by this action are converted to [`String`] and replace
247    /// the original execution result with a prepare-rollback failure.
248    ///
249    /// # Parameters
250    ///
251    /// * `rollback_prepare_action` - The action to run if the second condition
252    ///   check or task execution fails after prepare succeeds.
253    ///
254    /// # Returns
255    ///
256    /// This builder with prepare rollback configured.
257    ///
258    /// # Errors
259    ///
260    /// This builder method does not return errors. If
261    /// `rollback_prepare_action` later returns an error during execution, the
262    /// execution result becomes [`super::ExecutionResult::Failed`] with
263    /// [`super::ExecutorError::PrepareRollbackFailed`].
264    #[inline]
265    #[must_use = "assign or chain the returned builder"]
266    pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
267    where
268        Rn: Runnable<E> + Send + 'static,
269        E: Display,
270    {
271        let mut action = rollback_prepare_action;
272        self.rollback_prepare_action = Some(ArcRunnable::new(move || {
273            action
274                .run()
275                .map_err(|error| CallbackError::with_callback_type("prepare_rollback", error))
276        }));
277        self
278    }
279
280    /// Sets the commit action for a successfully completed prepare action.
281    ///
282    /// Errors returned by this action are converted to [`String`] and replace
283    /// an otherwise successful execution result with a prepare-commit failure.
284    ///
285    /// # Parameters
286    ///
287    /// * `commit_prepare_action` - The action to run if the task succeeds after
288    ///   prepare succeeds.
289    ///
290    /// # Returns
291    ///
292    /// This builder with prepare commit configured.
293    ///
294    /// # Errors
295    ///
296    /// This builder method does not return errors. If `commit_prepare_action`
297    /// later returns an error during execution, the execution result becomes
298    /// [`super::ExecutionResult::Failed`] with
299    /// [`super::ExecutorError::PrepareCommitFailed`].
300    #[inline]
301    #[must_use = "assign or chain the returned builder"]
302    pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
303    where
304        Rn: Runnable<E> + Send + 'static,
305        E: Display,
306    {
307        let mut action = commit_prepare_action;
308        self.commit_prepare_action = Some(ArcRunnable::new(move || {
309            action
310                .run()
311                .map_err(|error| CallbackError::with_callback_type("prepare_commit", error))
312        }));
313        self
314    }
315
316    /// Enables panic capture for tester, prepare callbacks, and task execution.
317    ///
318    /// When enabled, panic payloads are converted to
319    /// [`super::executor_error::ExecutorError::Panic`] and surfaced through
320    /// [`super::ExecutionResult`].
321    ///
322    /// # Returns
323    ///
324    /// This builder with panic capture enabled.
325    #[inline]
326    #[must_use = "assign or chain the returned builder"]
327    pub fn catch_panics(mut self) -> Self {
328        self.catch_panics = true;
329        self
330    }
331
332    /// Derives a builder with panic capture enabled or disabled for tester,
333    /// prepare callbacks, and task execution.
334    ///
335    /// # Parameters
336    ///
337    /// * `catch_panics` - `true` to capture panics as execution errors, or
338    ///   `false` to let panics unwind.
339    ///
340    /// # Returns
341    ///
342    /// A reconfigured builder with the updated panic-capture setting.
343    #[inline]
344    #[must_use = "assign or chain the returned builder"]
345    pub fn with_panic_capture(mut self, catch_panics: bool) -> Self {
346        self.catch_panics = catch_panics;
347        self
348    }
349
350    /// Disables panic capture for tester, prepare callbacks, and task execution.
351    ///
352    /// # Returns
353    ///
354    /// This builder with panic capture disabled.
355    #[inline]
356    #[must_use = "assign or chain the returned builder"]
357    pub fn disable_catch_panics(mut self) -> Self {
358        self.catch_panics = false;
359        self
360    }
361
362    /// Builds the reusable executor.
363    ///
364    /// # Returns
365    ///
366    /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
367    /// execution logger, and prepare lifecycle callbacks.
368    #[inline]
369    #[must_use = "use the returned executor"]
370    pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
371        DoubleCheckedLockExecutor::new(self)
372    }
373}