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 pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
85 self.logger.set_unmet_condition(Some(level), message);
86 self
87 }
88
89 /// Disables logging when the double-checked condition is not met.
90 ///
91 /// # Returns
92 ///
93 /// This builder with unmet-condition logging disabled.
94 #[inline]
95 pub fn disable_unmet_condition_logging(mut self) -> Self {
96 self.logger.disable_unmet_condition();
97 self
98 }
99
100 /// Configures logging when the prepare action fails.
101 ///
102 /// # Parameters
103 ///
104 /// * `level` - Log level used for prepare failure messages.
105 /// * `message_prefix` - Prefix placed before the prepare failure text.
106 ///
107 /// # Returns
108 ///
109 /// This builder with prepare failure logging configured.
110 #[inline]
111 pub fn log_prepare_failure(
112 mut self,
113 level: log::Level,
114 message_prefix: impl Into<String>,
115 ) -> Self {
116 self.logger.set_prepare_failure(Some(level), message_prefix);
117 self
118 }
119
120 /// Disables logging when the prepare action fails.
121 ///
122 /// # Returns
123 ///
124 /// This builder with prepare failure logging disabled.
125 #[inline]
126 pub fn disable_prepare_failure_logging(mut self) -> Self {
127 self.logger.disable_prepare_failure();
128 self
129 }
130
131 /// Configures logging when the prepare commit action fails.
132 ///
133 /// # Parameters
134 ///
135 /// * `level` - Log level used for prepare-commit failure messages.
136 /// * `message_prefix` - Prefix placed before the prepare-commit failure
137 /// text.
138 ///
139 /// # Returns
140 ///
141 /// This builder with prepare-commit failure logging configured.
142 #[inline]
143 pub fn log_prepare_commit_failure(
144 mut self,
145 level: log::Level,
146 message_prefix: impl Into<String>,
147 ) -> Self {
148 self.logger
149 .set_prepare_commit_failure(Some(level), message_prefix);
150 self
151 }
152
153 /// Disables logging when the prepare commit action fails.
154 ///
155 /// # Returns
156 ///
157 /// This builder with prepare-commit failure logging disabled.
158 #[inline]
159 pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
160 self.logger.disable_prepare_commit_failure();
161 self
162 }
163
164 /// Configures logging when the prepare rollback action fails.
165 ///
166 /// # Parameters
167 ///
168 /// * `level` - Log level used for prepare-rollback failure messages.
169 /// * `message_prefix` - Prefix placed before the prepare-rollback failure
170 /// text.
171 ///
172 /// # Returns
173 ///
174 /// This builder with prepare-rollback failure logging configured.
175 #[inline]
176 pub fn log_prepare_rollback_failure(
177 mut self,
178 level: log::Level,
179 message_prefix: impl Into<String>,
180 ) -> Self {
181 self.logger
182 .set_prepare_rollback_failure(Some(level), message_prefix);
183 self
184 }
185
186 /// Disables logging when the prepare rollback action fails.
187 ///
188 /// # Returns
189 ///
190 /// This builder with prepare-rollback failure logging disabled.
191 #[inline]
192 pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
193 self.logger.disable_prepare_rollback_failure();
194 self
195 }
196
197 /// Sets the prepare action.
198 ///
199 /// The action runs after the first condition check succeeds and before the
200 /// lock is acquired. If it succeeds, the executor will later run either
201 /// rollback or commit according to the final task result.
202 ///
203 /// Errors returned by this action are converted to [`String`] and reported
204 /// by execution methods as [`super::ExecutionResult::Failed`].
205 ///
206 /// # Parameters
207 ///
208 /// * `prepare_action` - The fallible action to run before locking.
209 ///
210 /// # Returns
211 ///
212 /// This builder with prepare configured.
213 ///
214 /// # Errors
215 ///
216 /// This builder method does not return errors. If `prepare_action` later
217 /// returns an error during execution, the execution result becomes
218 /// [`super::ExecutionResult::Failed`] with
219 /// [`super::ExecutorError::PrepareFailed`].
220 #[inline]
221 pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
222 where
223 Rn: Runnable<E> + Send + 'static,
224 E: Display,
225 {
226 let mut action = prepare_action;
227 self.prepare_action = Some(ArcRunnable::new(move || {
228 action
229 .run()
230 .map_err(|error| CallbackError::with_callback_type("prepare", error))
231 }));
232 self
233 }
234
235 /// Sets the rollback action for a successfully completed prepare action.
236 ///
237 /// Errors returned by this action are converted to [`String`] and replace
238 /// the original execution result with a prepare-rollback failure.
239 ///
240 /// # Parameters
241 ///
242 /// * `rollback_prepare_action` - The action to run if the second condition
243 /// check or task execution fails after prepare succeeds.
244 ///
245 /// # Returns
246 ///
247 /// This builder with prepare rollback configured.
248 ///
249 /// # Errors
250 ///
251 /// This builder method does not return errors. If
252 /// `rollback_prepare_action` later returns an error during execution, the
253 /// execution result becomes [`super::ExecutionResult::Failed`] with
254 /// [`super::ExecutorError::PrepareRollbackFailed`].
255 #[inline]
256 pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
257 where
258 Rn: Runnable<E> + Send + 'static,
259 E: Display,
260 {
261 let mut action = rollback_prepare_action;
262 self.rollback_prepare_action = Some(ArcRunnable::new(move || {
263 action
264 .run()
265 .map_err(|error| CallbackError::with_callback_type("prepare_rollback", error))
266 }));
267 self
268 }
269
270 /// Sets the commit action for a successfully completed prepare action.
271 ///
272 /// Errors returned by this action are converted to [`String`] and replace
273 /// an otherwise successful execution result with a prepare-commit failure.
274 ///
275 /// # Parameters
276 ///
277 /// * `commit_prepare_action` - The action to run if the task succeeds after
278 /// prepare succeeds.
279 ///
280 /// # Returns
281 ///
282 /// This builder with prepare commit configured.
283 ///
284 /// # Errors
285 ///
286 /// This builder method does not return errors. If `commit_prepare_action`
287 /// later returns an error during execution, the execution result becomes
288 /// [`super::ExecutionResult::Failed`] with
289 /// [`super::ExecutorError::PrepareCommitFailed`].
290 #[inline]
291 pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
292 where
293 Rn: Runnable<E> + Send + 'static,
294 E: Display,
295 {
296 let mut action = commit_prepare_action;
297 self.commit_prepare_action = Some(ArcRunnable::new(move || {
298 action
299 .run()
300 .map_err(|error| CallbackError::with_callback_type("prepare_commit", error))
301 }));
302 self
303 }
304
305 /// Enables panic capture for tester, prepare callbacks, and task execution.
306 ///
307 /// When enabled, panic payloads are converted to
308 /// [`super::executor_error::ExecutorError::Panic`] and surfaced through
309 /// [`super::ExecutionResult`].
310 ///
311 /// # Returns
312 ///
313 /// This builder with panic capture enabled.
314 #[inline]
315 #[must_use = "assign or chain the returned builder"]
316 pub fn catch_panics(mut self) -> Self {
317 self.catch_panics = true;
318 self
319 }
320
321 /// Derives a builder with panic capture enabled or disabled for tester,
322 /// prepare callbacks, and task execution.
323 ///
324 /// # Parameters
325 ///
326 /// * `catch_panics` - `true` to capture panics as execution errors, or
327 /// `false` to let panics unwind.
328 ///
329 /// # Returns
330 ///
331 /// A reconfigured builder with the updated panic-capture setting.
332 #[inline]
333 #[must_use = "assign or chain the returned builder"]
334 pub fn with_panic_capture(mut self, catch_panics: bool) -> Self {
335 self.catch_panics = catch_panics;
336 self
337 }
338
339 /// Disables panic capture for tester, prepare callbacks, and task execution.
340 ///
341 /// # Returns
342 ///
343 /// This builder with panic capture disabled.
344 #[inline]
345 #[must_use = "assign or chain the returned builder"]
346 pub fn disable_catch_panics(mut self) -> Self {
347 self.catch_panics = false;
348 self
349 }
350
351 /// Builds the reusable executor.
352 ///
353 /// # Returns
354 ///
355 /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
356 /// execution logger, and prepare lifecycle callbacks.
357 #[inline]
358 pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
359 DoubleCheckedLockExecutor::new(self)
360 }
361}