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