Skip to main content

qubit_rayon_executor/
rayon_executor_service_builder.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9use std::{
10    sync::Arc,
11    thread,
12};
13
14use rayon::ThreadPoolBuilder as RayonThreadPoolBuilder;
15
16use crate::{
17    rayon_executor_service::RayonExecutorService,
18    rayon_executor_service_build_error::RayonExecutorServiceBuildError,
19    rayon_executor_service_state::RayonExecutorServiceState,
20};
21
22/// Default thread name prefix used by [`RayonExecutorServiceBuilder`].
23const DEFAULT_THREAD_NAME_PREFIX: &str = "qubit-rayon-executor";
24
25/// Builder for [`RayonExecutorService`].
26///
27/// The default builder uses the available CPU parallelism and names workers
28/// with the `qubit-rayon-executor` prefix.
29#[derive(Debug, Clone)]
30pub struct RayonExecutorServiceBuilder {
31    /// Number of Rayon worker threads to create.
32    num_threads: usize,
33    /// Prefix used when naming Rayon worker threads.
34    thread_name_prefix: String,
35    /// Optional worker stack size in bytes.
36    stack_size: Option<usize>,
37}
38
39impl RayonExecutorServiceBuilder {
40    /// Sets the number of Rayon worker threads.
41    ///
42    /// # Parameters
43    ///
44    /// * `num_threads` - Number of Rayon worker threads.
45    ///
46    /// # Returns
47    ///
48    /// This builder for fluent configuration.
49    #[inline]
50    pub fn num_threads(mut self, num_threads: usize) -> Self {
51        self.num_threads = num_threads;
52        self
53    }
54
55    /// Sets the Rayon worker-thread name prefix.
56    ///
57    /// # Parameters
58    ///
59    /// * `prefix` - Prefix appended with the worker index.
60    ///
61    /// # Returns
62    ///
63    /// This builder for fluent configuration.
64    #[inline]
65    pub fn thread_name_prefix(mut self, prefix: &str) -> Self {
66        self.thread_name_prefix = prefix.to_owned();
67        self
68    }
69
70    /// Sets the Rayon worker-thread stack size.
71    ///
72    /// # Parameters
73    ///
74    /// * `stack_size` - Stack size in bytes for each Rayon worker.
75    ///
76    /// # Returns
77    ///
78    /// This builder for fluent configuration.
79    #[inline]
80    pub fn stack_size(mut self, stack_size: usize) -> Self {
81        self.stack_size = Some(stack_size);
82        self
83    }
84
85    /// Builds the configured Rayon executor service.
86    ///
87    /// # Returns
88    ///
89    /// `Ok(RayonExecutorService)` if the Rayon thread pool is created
90    /// successfully.
91    ///
92    /// # Errors
93    ///
94    /// Returns [`RayonExecutorServiceBuildError`] if the thread count or stack
95    /// size is zero, or if Rayon rejects the thread-pool configuration.
96    pub fn build(self) -> Result<RayonExecutorService, RayonExecutorServiceBuildError> {
97        if self.num_threads == 0 {
98            return Err(RayonExecutorServiceBuildError::ZeroThreadCount);
99        }
100        if self.stack_size == Some(0) {
101            return Err(RayonExecutorServiceBuildError::ZeroStackSize);
102        }
103        let prefix = self.thread_name_prefix;
104        let mut builder = RayonThreadPoolBuilder::new()
105            .num_threads(self.num_threads)
106            .thread_name(move |index| format!("{prefix}-{index}"));
107        if let Some(stack_size) = self.stack_size {
108            builder = builder.stack_size(stack_size);
109        }
110        let pool = Arc::new(builder.build()?);
111        Ok(RayonExecutorService {
112            pool,
113            state: Arc::new(RayonExecutorServiceState::new()),
114        })
115    }
116}
117
118impl Default for RayonExecutorServiceBuilder {
119    /// Creates a builder with CPU-parallelism defaults.
120    ///
121    /// # Returns
122    ///
123    /// A builder configured for the detected CPU parallelism.
124    fn default() -> Self {
125        Self {
126            num_threads: default_rayon_thread_count(),
127            thread_name_prefix: DEFAULT_THREAD_NAME_PREFIX.to_owned(),
128            stack_size: None,
129        }
130    }
131}
132
133/// Returns the default Rayon thread count for new builders.
134///
135/// # Returns
136///
137/// The available CPU parallelism, or `1` if it cannot be detected.
138fn default_rayon_thread_count() -> usize {
139    thread::available_parallelism()
140        .map(usize::from)
141        .unwrap_or(1)
142}