Skip to main content

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}