qubit_batch/execute/impls/parallel_batch_executor_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 ******************************************************************************/
10use std::{
11 sync::Arc,
12 time::Duration,
13};
14
15use qubit_progress::reporter::{
16 NoOpProgressReporter,
17 ProgressReporter,
18};
19
20use super::{
21 ParallelBatchExecutor,
22 ParallelBatchExecutorBuildError,
23};
24
25/// Builder for [`ParallelBatchExecutor`].
26///
27/// Use the builder when the default worker count, sequential fallback
28/// threshold, progress interval, or reporter should be customized.
29///
30/// ```rust
31/// use qubit_batch::ParallelBatchExecutor;
32///
33/// let executor = ParallelBatchExecutor::builder()
34/// .thread_count(2)
35/// .sequential_threshold(0)
36/// .build()
37/// .expect("parallel executor configuration should be valid");
38///
39/// assert_eq!(executor.thread_count(), 2);
40/// assert_eq!(executor.sequential_threshold(), 0);
41/// ```
42pub struct ParallelBatchExecutorBuilder {
43 /// Number of worker threads used for parallel executions.
44 thread_count: usize,
45 /// Maximum batch size that still uses sequential execution.
46 sequential_threshold: usize,
47 /// Minimum interval between progress callbacks.
48 report_interval: Duration,
49 /// Reporter receiving batch lifecycle callbacks.
50 reporter: Arc<dyn ProgressReporter>,
51}
52
53impl ParallelBatchExecutorBuilder {
54 /// Sets the worker-thread count.
55 ///
56 /// # Parameters
57 ///
58 /// * `thread_count` - Number of scoped worker threads to use.
59 ///
60 /// # Returns
61 ///
62 /// This builder for fluent configuration.
63 #[inline]
64 pub const fn thread_count(mut self, thread_count: usize) -> Self {
65 self.thread_count = thread_count;
66 self
67 }
68
69 /// Sets the sequential fallback threshold.
70 ///
71 /// # Parameters
72 ///
73 /// * `sequential_threshold` - Maximum batch size that still runs
74 /// sequentially.
75 ///
76 /// # Returns
77 ///
78 /// This builder for fluent configuration.
79 #[inline]
80 pub const fn sequential_threshold(mut self, sequential_threshold: usize) -> Self {
81 self.sequential_threshold = sequential_threshold;
82 self
83 }
84
85 /// Sets the progress-report interval.
86 ///
87 /// # Parameters
88 ///
89 /// * `report_interval` - Minimum interval between due-based running
90 /// progress events. Use [`Duration::ZERO`] to report at every
91 /// implementation-defined running progress point.
92 ///
93 /// # Returns
94 ///
95 /// This builder for fluent configuration.
96 #[inline]
97 pub const fn report_interval(mut self, report_interval: Duration) -> Self {
98 self.report_interval = report_interval;
99 self
100 }
101
102 /// Sets the progress reporter used by built executors.
103 ///
104 /// # Parameters
105 ///
106 /// * `reporter` - Reporter receiving batch lifecycle callbacks.
107 ///
108 /// # Returns
109 ///
110 /// This builder for fluent configuration.
111 #[inline]
112 pub fn reporter<R>(mut self, reporter: R) -> Self
113 where
114 R: ProgressReporter + 'static,
115 {
116 self.reporter = Arc::new(reporter);
117 self
118 }
119
120 /// Sets the shared progress reporter used by built executors.
121 ///
122 /// # Parameters
123 ///
124 /// * `reporter` - Shared reporter receiving batch lifecycle callbacks.
125 ///
126 /// # Returns
127 ///
128 /// This builder for fluent configuration.
129 #[inline]
130 pub fn reporter_arc(mut self, reporter: Arc<dyn ProgressReporter>) -> Self {
131 self.reporter = reporter;
132 self
133 }
134
135 /// Disables progress callbacks by using [`NoOpProgressReporter`].
136 ///
137 /// # Returns
138 ///
139 /// This builder for fluent configuration.
140 #[inline]
141 pub fn no_reporter(mut self) -> Self {
142 self.reporter = Arc::new(NoOpProgressReporter);
143 self
144 }
145
146 /// Builds a validated [`ParallelBatchExecutor`].
147 ///
148 /// # Returns
149 ///
150 /// A parallel batch executor when the configuration is valid.
151 ///
152 /// # Errors
153 ///
154 /// Returns [`ParallelBatchExecutorBuildError`] when the worker count is
155 /// zero.
156 pub fn build(self) -> Result<ParallelBatchExecutor, ParallelBatchExecutorBuildError> {
157 if self.thread_count == 0 {
158 return Err(ParallelBatchExecutorBuildError::ZeroThreadCount);
159 }
160 Ok(ParallelBatchExecutor {
161 thread_count: self.thread_count,
162 sequential_threshold: self.sequential_threshold,
163 report_interval: self.report_interval,
164 reporter: self.reporter,
165 })
166 }
167}
168
169impl Default for ParallelBatchExecutorBuilder {
170 /// Creates a builder with default parallel batch settings.
171 ///
172 /// # Returns
173 ///
174 /// A builder using available parallelism, five-second progress intervals,
175 /// sequential fallback for batches at or below [`ParallelBatchExecutor::DEFAULT_SEQUENTIAL_THRESHOLD`],
176 /// and no-op reporting.
177 fn default() -> Self {
178 Self {
179 thread_count: ParallelBatchExecutor::default_thread_count(),
180 sequential_threshold: ParallelBatchExecutor::DEFAULT_SEQUENTIAL_THRESHOLD,
181 report_interval: ParallelBatchExecutor::DEFAULT_REPORT_INTERVAL,
182 reporter: Arc::new(NoOpProgressReporter),
183 }
184 }
185}