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}