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