Skip to main content

qubit_dcl/double_checked/
executor_lock_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//! Builder state after a lock has been attached for
11//! [`super::DoubleCheckedLockExecutor`].
12//!
13
14use std::marker::PhantomData;
15
16use qubit_function::Tester;
17
18use super::{
19    ExecutionLogger,
20    executor_ready_builder::ExecutorReadyBuilder,
21};
22use crate::lock::Lock;
23
24/// Builder state after a lock has been attached.
25///
26/// Call [`Self::when`] to configure the required condition tester.
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 ExecutorLockBuilder<L, T> {
35    /// The lock to store in the executor.
36    pub(in crate::double_checked) lock: L,
37
38    /// Logger carried forward to the ready builder state.
39    pub(in crate::double_checked) logger: ExecutionLogger,
40
41    /// Whether panics from tester, callbacks, and task are captured as result errors.
42    pub(in crate::double_checked) catch_panics: bool,
43
44    /// Carries the protected data type.
45    pub(in crate::double_checked) _phantom: PhantomData<fn() -> T>,
46}
47
48impl<L, T> ExecutorLockBuilder<L, T>
49where
50    L: Lock<T>,
51{
52    /// Configures logging when the double-checked condition is not met.
53    #[inline]
54    pub fn log_unmet_condition(mut self, level: log::Level, message: impl Into<String>) -> Self {
55        self.logger.set_unmet_condition(Some(level), message);
56        self
57    }
58
59    /// Disables logging when the double-checked condition is not met.
60    #[inline]
61    pub fn disable_unmet_condition_logging(mut self) -> Self {
62        self.logger.disable_unmet_condition();
63        self
64    }
65
66    /// Configures logging when the prepare action fails.
67    #[inline]
68    pub fn log_prepare_failure(
69        mut self,
70        level: log::Level,
71        message_prefix: impl Into<String>,
72    ) -> Self {
73        self.logger.set_prepare_failure(Some(level), message_prefix);
74        self
75    }
76
77    /// Disables logging when the prepare action fails.
78    #[inline]
79    pub fn disable_prepare_failure_logging(mut self) -> Self {
80        self.logger.disable_prepare_failure();
81        self
82    }
83
84    /// Configures logging when the prepare commit action fails.
85    #[inline]
86    pub fn log_prepare_commit_failure(
87        mut self,
88        level: log::Level,
89        message_prefix: impl Into<String>,
90    ) -> Self {
91        self.logger
92            .set_prepare_commit_failure(Some(level), message_prefix);
93        self
94    }
95
96    /// Disables logging when the prepare commit action fails.
97    #[inline]
98    pub fn disable_prepare_commit_failure_logging(mut self) -> Self {
99        self.logger.disable_prepare_commit_failure();
100        self
101    }
102
103    /// Configures logging when the prepare rollback action fails.
104    #[inline]
105    pub fn log_prepare_rollback_failure(
106        mut self,
107        level: log::Level,
108        message_prefix: impl Into<String>,
109    ) -> Self {
110        self.logger
111            .set_prepare_rollback_failure(Some(level), message_prefix);
112        self
113    }
114
115    /// Disables logging when the prepare rollback action fails.
116    #[inline]
117    pub fn disable_prepare_rollback_failure_logging(mut self) -> Self {
118        self.logger.disable_prepare_rollback_failure();
119        self
120    }
121
122    /// Configures the required double-checked condition.
123    ///
124    /// The tester is executed outside and inside the lock. State read by the
125    /// outside check must be safe to access without this executor's lock.
126    ///
127    /// # Parameters
128    ///
129    /// * `tester` - The reusable condition tester.
130    ///
131    /// # Returns
132    ///
133    /// The builder state that can configure prepare callbacks and build the
134    /// executor.
135    #[inline]
136    pub fn when<Tst>(self, tester: Tst) -> ExecutorReadyBuilder<L, T>
137    where
138        Tst: Tester + Send + Sync + 'static,
139    {
140        ExecutorReadyBuilder {
141            lock: self.lock,
142            tester: tester.into_arc(),
143            logger: self.logger,
144            prepare_action: None,
145            rollback_prepare_action: None,
146            commit_prepare_action: None,
147            catch_panics: self.catch_panics,
148            _phantom: PhantomData,
149        }
150    }
151
152    /// Enables panic capture for tester, prepare callbacks, and task execution.
153    #[inline]
154    pub fn catch_panics(mut self) -> Self {
155        self.catch_panics = true;
156        self
157    }
158
159    /// Sets whether panic capture for tester, prepare callbacks, and task
160    /// execution is enabled.
161    #[inline]
162    pub fn set_catch_panics(mut self, catch_panics: bool) -> Self {
163        self.catch_panics = catch_panics;
164        self
165    }
166
167    /// Disables panic capture for tester, prepare callbacks, and task execution.
168    #[inline]
169    pub fn disable_catch_panics(mut self) -> Self {
170        self.catch_panics = false;
171        self
172    }
173}