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