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 #[inline]
75 pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
76 self.logger.set_unmet_condition(Some(level), message);
77 self
78 }
79
80 /// Disables logging when the double-checked condition is not met.
81 #[inline]
82 pub fn disable_unmet_condition_logging(mut self) -> Self {
83 self.logger.disable_unmet_condition();
84 self
85 }
86
87 /// Configures logging when the prepare action fails.
88 #[inline]
89 pub fn log_prepare_failure(
90 mut self,
91 level: log::Level,
92 message_prefix: impl Into<String>,
93 ) -> Self {
94 self.logger.set_prepare_failure(Some(level), message_prefix);
95 self
96 }
97
98 /// Disables logging when the prepare action fails.
99 #[inline]
100 pub fn disable_prepare_failure_logging(mut self) -> Self {
101 self.logger.disable_prepare_failure();
102 self
103 }
104
105 /// Configures logging when the prepare commit action fails.
106 #[inline]
107 pub fn log_prepare_commit_failure(
108 mut self,
109 level: log::Level,
110 message_prefix: impl Into<String>,
111 ) -> Self {
112 self.logger
113 .set_prepare_commit_failure(Some(level), message_prefix);
114 self
115 }
116
117 /// Disables logging when the prepare commit action fails.
118 #[inline]
119 pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
120 self.logger.disable_prepare_commit_failure();
121 self
122 }
123
124 /// Configures logging when the prepare rollback action fails.
125 #[inline]
126 pub fn log_prepare_rollback_failure(
127 mut self,
128 level: log::Level,
129 message_prefix: impl Into<String>,
130 ) -> Self {
131 self.logger
132 .set_prepare_rollback_failure(Some(level), message_prefix);
133 self
134 }
135
136 /// Disables logging when the prepare rollback action fails.
137 #[inline]
138 pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
139 self.logger.disable_prepare_rollback_failure();
140 self
141 }
142
143 /// Sets the prepare action.
144 ///
145 /// The action runs after the first condition check succeeds and before the
146 /// lock is acquired. If it succeeds, the executor will later run either
147 /// rollback or commit according to the final task result.
148 ///
149 /// Errors returned by this action are converted to [`String`] and reported
150 /// by execution methods as [`super::ExecutionResult::Failed`].
151 ///
152 /// # Parameters
153 ///
154 /// * `prepare_action` - The fallible action to run before locking.
155 ///
156 /// # Returns
157 ///
158 /// This builder with prepare configured.
159 #[inline]
160 pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
161 where
162 Rn: Runnable<E> + Send + 'static,
163 E: Display,
164 {
165 let mut action = prepare_action;
166 self.prepare_action = Some(ArcRunnable::new(move || {
167 action
168 .run()
169 .map_err(|error| CallbackError::with_type("prepare", error))
170 }));
171 self
172 }
173
174 /// Sets the rollback action for a successfully completed prepare action.
175 ///
176 /// Errors returned by this action are converted to [`String`] and replace
177 /// the original execution result with a prepare-rollback failure.
178 ///
179 /// # Parameters
180 ///
181 /// * `rollback_prepare_action` - The action to run if the second condition
182 /// check or task execution fails after prepare succeeds.
183 ///
184 /// # Returns
185 ///
186 /// This builder with prepare rollback configured.
187 #[inline]
188 pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
189 where
190 Rn: Runnable<E> + Send + 'static,
191 E: Display,
192 {
193 let mut action = rollback_prepare_action;
194 self.rollback_prepare_action = Some(ArcRunnable::new(move || {
195 action
196 .run()
197 .map_err(|error| CallbackError::with_type("prepare_rollback", error))
198 }));
199 self
200 }
201
202 /// Sets the commit action for a successfully completed prepare action.
203 ///
204 /// Errors returned by this action are converted to [`String`] and replace
205 /// an otherwise successful execution result with a prepare-commit failure.
206 ///
207 /// # Parameters
208 ///
209 /// * `commit_prepare_action` - The action to run if the task succeeds after
210 /// prepare succeeds.
211 ///
212 /// # Returns
213 ///
214 /// This builder with prepare commit configured.
215 #[inline]
216 pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
217 where
218 Rn: Runnable<E> + Send + 'static,
219 E: Display,
220 {
221 let mut action = commit_prepare_action;
222 self.commit_prepare_action = Some(ArcRunnable::new(move || {
223 action
224 .run()
225 .map_err(|error| CallbackError::with_type("prepare_commit", error))
226 }));
227 self
228 }
229
230 /// Enables panic capture for tester, prepare callbacks, and task execution.
231 ///
232 /// When enabled, panic payloads are converted to
233 /// [`super::executor_error::ExecutorError::Panic`] and surfaced through
234 /// [`super::ExecutionResult`].
235 #[inline]
236 pub fn catch_panics(mut self) -> Self {
237 self.catch_panics = true;
238 self
239 }
240
241 /// Sets whether panic capture for tester, prepare callbacks, and task
242 /// execution is enabled.
243 #[inline]
244 pub fn set_catch_panics(mut self, catch_panics: bool) -> Self {
245 self.catch_panics = catch_panics;
246 self
247 }
248
249 /// Disables panic capture for tester, prepare callbacks, and task execution.
250 #[inline]
251 pub fn disable_catch_panics(mut self) -> Self {
252 self.catch_panics = false;
253 self
254 }
255
256 /// Builds the reusable executor.
257 ///
258 /// # Returns
259 ///
260 /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
261 /// execution logger, and prepare lifecycle callbacks.
262 #[inline]
263 pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
264 DoubleCheckedLockExecutor::new(self)
265 }
266}