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