qubit_thread_pool/fixed_thread_pool_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 for [`super::FixedThreadPool`].
11
12use std::thread;
13
14use super::fixed_thread_pool::FixedThreadPool;
15use super::thread_pool::ThreadPoolBuildError;
16
17/// Default thread name prefix used by [`FixedThreadPoolBuilder`].
18const DEFAULT_FIXED_THREAD_NAME_PREFIX: &str = "qubit-fixed-thread-pool";
19
20/// Builder for [`FixedThreadPool`].
21///
22/// The fixed pool prestarts exactly `pool_size` workers and never changes that
23/// count during runtime.
24#[derive(Debug, Clone)]
25pub struct FixedThreadPoolBuilder {
26 /// Number of workers to prestart.
27 pool_size: usize,
28 /// Optional maximum queued task count.
29 queue_capacity: Option<usize>,
30 /// Prefix used for worker thread names.
31 thread_name_prefix: String,
32 /// Optional worker stack size.
33 stack_size: Option<usize>,
34}
35
36impl FixedThreadPoolBuilder {
37 /// Creates a builder with CPU parallelism defaults.
38 ///
39 /// # Returns
40 ///
41 /// A builder with a fixed worker count equal to available parallelism.
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 /// Sets the fixed worker count.
47 ///
48 /// # Parameters
49 ///
50 /// * `pool_size` - Number of workers to create.
51 ///
52 /// # Returns
53 ///
54 /// This builder for fluent configuration.
55 pub fn pool_size(mut self, pool_size: usize) -> Self {
56 self.pool_size = pool_size;
57 self
58 }
59
60 /// Sets a bounded queue capacity.
61 ///
62 /// # Parameters
63 ///
64 /// * `capacity` - Maximum number of queued tasks.
65 ///
66 /// # Returns
67 ///
68 /// This builder for fluent configuration.
69 pub fn queue_capacity(mut self, capacity: usize) -> Self {
70 self.queue_capacity = Some(capacity);
71 self
72 }
73
74 /// Uses an unbounded queue.
75 ///
76 /// # Returns
77 ///
78 /// This builder for fluent configuration.
79 pub fn unbounded_queue(mut self) -> Self {
80 self.queue_capacity = None;
81 self
82 }
83
84 /// Sets the worker thread name prefix.
85 ///
86 /// # Parameters
87 ///
88 /// * `prefix` - Prefix used for worker thread names.
89 ///
90 /// # Returns
91 ///
92 /// This builder for fluent configuration.
93 pub fn thread_name_prefix(mut self, prefix: &str) -> Self {
94 self.thread_name_prefix = prefix.to_owned();
95 self
96 }
97
98 /// Sets the worker stack size.
99 ///
100 /// # Parameters
101 ///
102 /// * `stack_size` - Stack size in bytes.
103 ///
104 /// # Returns
105 ///
106 /// This builder for fluent configuration.
107 pub fn stack_size(mut self, stack_size: usize) -> Self {
108 self.stack_size = Some(stack_size);
109 self
110 }
111
112 /// Builds the configured fixed thread pool.
113 ///
114 /// # Returns
115 ///
116 /// A fixed pool with all workers prestarted.
117 ///
118 /// # Errors
119 ///
120 /// Returns [`ThreadPoolBuildError`] when configuration is invalid or a
121 /// worker thread cannot be spawned.
122 pub fn build(self) -> Result<FixedThreadPool, ThreadPoolBuildError> {
123 self.validate()?;
124 FixedThreadPool::build_with_options(
125 self.pool_size,
126 self.queue_capacity,
127 self.thread_name_prefix,
128 self.stack_size,
129 )
130 }
131
132 /// Validates this builder configuration.
133 ///
134 /// # Returns
135 ///
136 /// `Ok(())` when configuration is valid.
137 ///
138 /// # Errors
139 ///
140 /// Returns [`ThreadPoolBuildError`] for zero pool size, zero queue capacity,
141 /// or zero stack size.
142 fn validate(&self) -> Result<(), ThreadPoolBuildError> {
143 if self.pool_size == 0 {
144 return Err(ThreadPoolBuildError::ZeroMaximumPoolSize);
145 }
146 if self.queue_capacity == Some(0) {
147 return Err(ThreadPoolBuildError::ZeroQueueCapacity);
148 }
149 if self.stack_size == Some(0) {
150 return Err(ThreadPoolBuildError::ZeroStackSize);
151 }
152 Ok(())
153 }
154}
155
156impl Default for FixedThreadPoolBuilder {
157 /// Creates a builder using available CPU parallelism.
158 ///
159 /// # Returns
160 ///
161 /// Default fixed-pool builder.
162 fn default() -> Self {
163 Self {
164 pool_size: default_fixed_pool_size(),
165 queue_capacity: None,
166 thread_name_prefix: DEFAULT_FIXED_THREAD_NAME_PREFIX.to_owned(),
167 stack_size: None,
168 }
169 }
170}
171
172/// Returns the default fixed worker count.
173///
174/// # Returns
175///
176/// Available CPU parallelism, or `1` if it cannot be detected.
177fn default_fixed_pool_size() -> usize {
178 thread::available_parallelism()
179 .map(usize::from)
180 .unwrap_or(1)
181}