Skip to main content

xtalforge_core/
parallel.rs

1//! Thread-pool options shared by the surfaces (Task 11.1.2).
2
3/// Worker-thread policy for the algorithms that have a parallel path.
4#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
5pub struct ParallelOptions {
6    /// Number of workers; `None` uses the Rayon default.
7    pub threads: Option<usize>,
8}
9
10impl ParallelOptions {
11    /// Creates options with an optional worker count.
12    #[must_use]
13    pub const fn new(threads: Option<usize>) -> Self {
14        Self { threads }
15    }
16
17    /// Runs `function` inside a scoped pool with the requested worker count.
18    ///
19    /// Results are independent of the thread count because the parallel
20    /// reductions keep a fixed order (AGENTS.md rule 6).
21    ///
22    /// # Errors
23    ///
24    /// Returns a message when the pool cannot be built.
25    #[cfg(feature = "parallel")]
26    pub fn install<T, F>(&self, function: F) -> Result<T, String>
27    where
28        F: FnOnce() -> T + Send,
29        T: Send,
30    {
31        match self.threads {
32            None => Ok(function()),
33            Some(threads) => {
34                let pool = rayon::ThreadPoolBuilder::new()
35                    .num_threads(threads)
36                    .build()
37                    .map_err(|error| format!("could not build the thread pool: {error}"))?;
38                Ok(pool.install(function))
39            }
40        }
41    }
42
43    /// Runs `function` directly when the parallel feature is off.
44    ///
45    /// # Errors
46    ///
47    /// Never returns an error in this build.
48    #[cfg(not(feature = "parallel"))]
49    pub fn install<T, F>(&self, function: F) -> Result<T, String>
50    where
51        F: FnOnce() -> T + Send,
52        T: Send,
53    {
54        Ok(function())
55    }
56}
57
58/// Installs the process-wide Rayon pool with `threads` workers.
59///
60/// Returns `true` when the pool was installed and `false` when this build has
61/// no parallel feature. A pool can be installed only once per process.
62///
63/// # Errors
64///
65/// Returns a message when the pool was already installed or cannot be built.
66#[cfg(feature = "parallel")]
67pub fn set_global_threads(threads: usize) -> Result<bool, String> {
68    rayon::ThreadPoolBuilder::new()
69        .num_threads(threads)
70        .build_global()
71        .map(|()| true)
72        .map_err(|error| format!("could not install the global thread pool: {error}"))
73}
74
75/// No-op when the parallel feature is off.
76///
77/// # Errors
78///
79/// Never returns an error in this build.
80#[cfg(not(feature = "parallel"))]
81pub fn set_global_threads(_threads: usize) -> Result<bool, String> {
82    Ok(false)
83}