qubit_lock/double_checked/executor_ready_builder.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Ready builder for [`super::DoubleCheckedLockExecutor`] (tester set, optional
10//! prepare hooks).
11//!
12//! # Author
13//!
14//! Haixing Hu
15
16use std::{
17 fmt::Display,
18 marker::PhantomData,
19};
20
21use qubit_function::{
22 ArcRunnable,
23 ArcTester,
24 Runnable,
25};
26
27use super::{
28 ExecutionLogger,
29 double_checked_lock_executor::DoubleCheckedLockExecutor,
30};
31use crate::lock::Lock;
32
33/// Builder state after the required condition tester has been configured.
34///
35/// This state can configure prepare lifecycle callbacks and build the final
36/// [`DoubleCheckedLockExecutor`].
37///
38/// # Type Parameters
39///
40/// * `L` - The lock type implementing [`Lock<T>`].
41/// * `T` - The data type protected by the lock.
42///
43/// # Author
44///
45/// Haixing Hu
46#[derive(Clone)]
47pub struct ExecutorReadyBuilder<L, T> {
48 /// The lock to store in the executor.
49 pub(in crate::double_checked) lock: L,
50
51 /// Required condition tester.
52 pub(in crate::double_checked) tester: ArcTester,
53
54 /// Logger used by the executor.
55 pub(in crate::double_checked) logger: ExecutionLogger,
56
57 /// Optional action executed after the first check and before locking.
58 pub(in crate::double_checked) prepare_action: Option<ArcRunnable<String>>,
59
60 /// Optional action executed when prepare must be rolled back.
61 pub(in crate::double_checked) rollback_prepare_action: Option<ArcRunnable<String>>,
62
63 /// Optional action executed when prepare should be committed.
64 pub(in crate::double_checked) commit_prepare_action: Option<ArcRunnable<String>>,
65
66 /// Carries the protected data type.
67 pub(in crate::double_checked) _phantom: PhantomData<fn() -> T>,
68}
69
70impl<L, T> ExecutorReadyBuilder<L, T>
71where
72 L: Lock<T>,
73{
74 /// Configures logging when the double-checked condition is not met.
75 #[inline]
76 pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
77 self.logger.set_unmet_condition(Some(level), message);
78 self
79 }
80
81 /// Configures logging when the prepare action fails.
82 #[inline]
83 pub fn log_prepare_failure(
84 mut self,
85 level: log::Level,
86 message_prefix: impl Into<String>,
87 ) -> Self {
88 self.logger.set_prepare_failure(Some(level), message_prefix);
89 self
90 }
91
92 /// Configures logging when the prepare commit action fails.
93 #[inline]
94 pub fn log_prepare_commit_failure(
95 mut self,
96 level: log::Level,
97 message_prefix: impl Into<String>,
98 ) -> Self {
99 self.logger
100 .set_prepare_commit_failure(Some(level), message_prefix);
101 self
102 }
103
104 /// Configures logging when the prepare rollback action fails.
105 #[inline]
106 pub fn log_prepare_rollback_failure(
107 mut self,
108 level: log::Level,
109 message_prefix: impl Into<String>,
110 ) -> Self {
111 self.logger
112 .set_prepare_rollback_failure(Some(level), message_prefix);
113 self
114 }
115
116 /// Sets the prepare action.
117 ///
118 /// The action runs after the first condition check succeeds and before the
119 /// lock is acquired. If it succeeds, the executor will later run either
120 /// rollback or commit according to the final task result.
121 ///
122 /// Errors returned by this action are converted to [`String`] and reported
123 /// by execution methods as [`super::ExecutionResult::Failed`].
124 ///
125 /// # Parameters
126 ///
127 /// * `prepare_action` - The fallible action to run before locking.
128 ///
129 /// # Returns
130 ///
131 /// This builder with prepare configured.
132 #[inline]
133 pub fn prepare<Rn, E>(mut self, prepare_action: Rn) -> Self
134 where
135 Rn: Runnable<E> + Send + 'static,
136 E: Display + Send + 'static,
137 {
138 let mut action = prepare_action;
139 self.prepare_action = Some(ArcRunnable::new(move || {
140 action.run().map_err(|error| error.to_string())
141 }));
142 self
143 }
144
145 /// Sets the rollback action for a successfully completed prepare action.
146 ///
147 /// Errors returned by this action are converted to [`String`] and replace
148 /// the original execution result with a prepare-rollback failure.
149 ///
150 /// # Parameters
151 ///
152 /// * `rollback_prepare_action` - The action to run if the second condition
153 /// check or task execution fails after prepare succeeds.
154 ///
155 /// # Returns
156 ///
157 /// This builder with prepare rollback configured.
158 #[inline]
159 pub fn rollback_prepare<Rn, E>(mut self, rollback_prepare_action: Rn) -> Self
160 where
161 Rn: Runnable<E> + Send + 'static,
162 E: Display + Send + 'static,
163 {
164 let mut action = rollback_prepare_action;
165 self.rollback_prepare_action = Some(ArcRunnable::new(move || {
166 action.run().map_err(|error| error.to_string())
167 }));
168 self
169 }
170
171 /// Sets the commit action for a successfully completed prepare action.
172 ///
173 /// Errors returned by this action are converted to [`String`] and replace
174 /// an otherwise successful execution result with a prepare-commit failure.
175 ///
176 /// # Parameters
177 ///
178 /// * `commit_prepare_action` - The action to run if the task succeeds after
179 /// prepare succeeds.
180 ///
181 /// # Returns
182 ///
183 /// This builder with prepare commit configured.
184 #[inline]
185 pub fn commit_prepare<Rn, E>(mut self, commit_prepare_action: Rn) -> Self
186 where
187 Rn: Runnable<E> + Send + 'static,
188 E: Display + Send + 'static,
189 {
190 let mut action = commit_prepare_action;
191 self.commit_prepare_action = Some(ArcRunnable::new(move || {
192 action.run().map_err(|error| error.to_string())
193 }));
194 self
195 }
196
197 /// Builds the reusable executor.
198 ///
199 /// # Returns
200 ///
201 /// A [`DoubleCheckedLockExecutor`] containing the configured lock, tester,
202 /// execution logger, and prepare lifecycle callbacks.
203 #[inline]
204 pub fn build(self) -> DoubleCheckedLockExecutor<L, T> {
205 DoubleCheckedLockExecutor::new(self)
206 }
207}