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}