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::{fmt::Display, marker::PhantomData};
15
16use qubit_function::{ArcRunnable, ArcTester, Runnable};
17
18use super::{
19 CallbackError, ExecutionLogger, double_checked_lock_executor::DoubleCheckedLockExecutor,
20};
21use crate::lock::Lock;
22
23/// Builder state after the required condition tester has been configured.
24///
25/// This state can configure prepare lifecycle callbacks and build the final
26/// [`DoubleCheckedLockExecutor`].
27///
28/// # Type Parameters
29///
30/// * `L` - The lock type implementing [`Lock<T>`].
31/// * `T` - The data type protected by the lock.
32///
33#[derive(Clone)]
34pub struct ExecutorReadyBuilder<L, T> {
35 /// The lock to store in the executor.
36 pub(in crate::double_checked) lock: L,
37
38 /// Required condition tester.
39 pub(in crate::double_checked) tester: ArcTester,
40
41 /// Logger used by the executor.
42 pub(in crate::double_checked) logger: ExecutionLogger,
43
44 /// Optional action executed after the first check and before locking.
45 pub(in crate::double_checked) prepare_action: Option<ArcRunnable<CallbackError>>,
46
47 /// Optional action executed when prepare must be rolled back.
48 pub(in crate::double_checked) rollback_prepare_action: Option<ArcRunnable<CallbackError>>,
49
50 /// Optional action executed when prepare should be committed.
51 pub(in crate::double_checked) commit_prepare_action: Option<ArcRunnable<CallbackError>>,
52
53 /// Whether panics from tester, callbacks, and task are converted to errors.
54 pub(in crate::double_checked) catch_panics: bool,
55
56 /// Carries the protected data type.
57 pub(in crate::double_checked) _phantom: PhantomData<fn() -> T>,
58}
59
60impl<L, T> ExecutorReadyBuilder<L, T>
61where
62 L: Lock<T>,
63{
64 /// Configures logging when the double-checked condition is not met.
65 #[inline]
66 pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
67 self.logger.set_unmet_condition(Some(level), message);
68 self
69 }
70
71 /// Disables logging when the double-checked condition is not met.
72 #[inline]
73 pub fn disable_unmet_condition_logging(mut self) -> Self {
74 self.logger.disable_unmet_condition();
75 self
76 }
77
78 /// Configures logging when the prepare action fails.
79 #[inline]
80 pub fn log_prepare_failure(
81 mut self,
82 level: log::Level,
83 message_prefix: impl Into<String>,
84 ) -> Self {
85 self.logger.set_prepare_failure(Some(level), message_prefix);
86 self
87 }
88
89 /// Disables logging when the prepare action fails.
90 #[inline]
91 pub fn disable_prepare_failure_logging(mut self) -> Self {
92 self.logger.disable_prepare_failure();
93 self
94 }
95
96 /// Configures logging when the prepare commit action fails.
97 #[inline]
98 pub fn log_prepare_commit_failure(
99 mut self,
100 level: log::Level,
101 message_prefix: impl Into<String>,
102 ) -> Self {
103 self.logger
104 .set_prepare_commit_failure(Some(level), message_prefix);
105 self
106 }
107
108 /// Disables logging when the prepare commit action fails.
109 #[inline]
110 pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
111 self.logger.disable_prepare_commit_failure();
112 self
113 }
114
115 /// Configures logging when the prepare rollback action fails.
116 #[inline]
117 pub fn log_prepare_rollback_failure(
118 mut self,
119 level: log::Level,
120 message_prefix: impl Into<String>,
121 ) -> Self {
122 self.logger
123 .set_prepare_rollback_failure(Some(level), message_prefix);
124 self
125 }
126
127 /// Disables logging when the prepare rollback action fails.
128 #[inline]
129 pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
130 self.logger.disable_prepare_rollback_failure();
131 self
132 }
133
134 /// Sets the prepare action.
135 ///
136 /// The action runs after the first condition check succeeds and before the
137 /// lock is acquired. If it succeeds, the executor will later run either
138 /// rollback or commit according to the final task result.
139 ///
140 /// Errors returned by this action are converted to [`String`] and reported
141 /// by execution methods as [`super::ExecutionResult::Failed`].
142 ///
143 /// # Parameters
144 ///
145 /// * `prepare_action` - The fallible action to run before locking.
146 ///
147 /// # Returns
148 ///
149 /// This builder with prepare configured.
150 #[inline]
151 pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
152 where
153 Rn: Runnable<E> + Send + 'static,
154 E: Display,
155 {
156 let mut action = prepare_action;
157 self.prepare_action = Some(ArcRunnable::new(move || {
158 action
159 .run()
160 .map_err(|error| CallbackError::with_type("prepare", error))
161 }));
162 self
163 }
164
165 /// Sets the rollback action for a successfully completed prepare action.
166 ///
167 /// Errors returned by this action are converted to [`String`] and replace
168 /// the original execution result with a prepare-rollback failure.
169 ///
170 /// # Parameters
171 ///
172 /// * `rollback_prepare_action` - The action to run if the second condition
173 /// check or task execution fails after prepare succeeds.
174 ///
175 /// # Returns
176 ///
177 /// This builder with prepare rollback configured.
178 #[inline]
179 pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
180 where
181 Rn: Runnable<E> + Send + 'static,
182 E: Display,
183 {
184 let mut action = rollback_prepare_action;
185 self.rollback_prepare_action = Some(ArcRunnable::new(move || {
186 action
187 .run()
188 .map_err(|error| CallbackError::with_type("prepare_rollback", error))
189 }));
190 self
191 }
192
193 /// Sets the commit action for a successfully completed prepare action.
194 ///
195 /// Errors returned by this action are converted to [`String`] and replace
196 /// an otherwise successful execution result with a prepare-commit failure.
197 ///
198 /// # Parameters
199 ///
200 /// * `commit_prepare_action` - The action to run if the task succeeds after
201 /// prepare succeeds.
202 ///
203 /// # Returns
204 ///
205 /// This builder with prepare commit configured.
206 #[inline]
207 pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
208 where
209 Rn: Runnable<E> + Send + 'static,
210 E: Display,
211 {
212 let mut action = commit_prepare_action;
213 self.commit_prepare_action = Some(ArcRunnable::new(move || {
214 action
215 .run()
216 .map_err(|error| CallbackError::with_type("prepare_commit", error))
217 }));
218 self
219 }
220
221 /// Enables panic capture for tester, prepare callbacks, and task execution.
222 ///
223 /// When enabled, panic payloads are converted to
224 /// [`super::executor_error::ExecutorError::Panic`] and surfaced through
225 /// [`super::ExecutionResult`].
226 #[inline]
227 pub fn catch_panics(mut self) -> Self {
228 self.catch_panics = true;
229 self
230 }
231
232 /// Sets whether panic capture for tester, prepare callbacks, and task
233 /// execution is enabled.
234 #[inline]
235 pub fn set_catch_panics(mut self, catch_panics: bool) -> Self {
236 self.catch_panics = catch_panics;
237 self
238 }
239
240 /// Disables panic capture for tester, prepare callbacks, and task execution.
241 #[inline]
242 pub fn disable_catch_panics(mut self) -> Self {
243 self.catch_panics = false;
244 self
245 }
246
247 /// Builds the reusable executor.
248 ///
249 /// # Returns
250 ///
251 /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
252 /// execution logger, and prepare lifecycle callbacks.
253 #[inline]
254 pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
255 DoubleCheckedLockExecutor::new(self)
256 }
257}