Skip to main content

oar_ocr_core/core/config/
parallel.rs

1//! Shared parallel processing configuration types.
2
3use serde::{Deserialize, Serialize};
4
5/// Centralized configuration for parallel processing behavior across the OCR pipeline.
6///
7/// This struct consolidates parallel processing configuration that was previously
8/// scattered across different components, providing a unified way to tune parallelism
9/// behavior throughout the OCR pipeline.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ParallelPolicy {
12    /// Maximum number of threads to use for parallel processing.
13    /// If None, rayon will use the default thread pool size (typically number of CPU cores).
14    /// Default: None (use rayon's default)
15    #[serde(default)]
16    pub max_threads: Option<usize>,
17
18    /// Threshold for general utility operations like image loading (<= this uses sequential)
19    /// Default: 4 (matches DEFAULT_PARALLEL_THRESHOLD constant)
20    #[serde(default = "ParallelPolicy::default_utility_threshold")]
21    pub utility_threshold: usize,
22
23    /// Threshold for postprocessing operations based on pixel area (<= this uses sequential)
24    /// Default: 8000 (use sequential for regions with <= 8000 pixels, parallel for larger)
25    #[serde(default = "ParallelPolicy::default_postprocess_pixel_threshold")]
26    pub postprocess_pixel_threshold: usize,
27}
28
29impl ParallelPolicy {
30    /// Create a new ParallelPolicy with default values.
31    pub fn new() -> Self {
32        Self::default()
33    }
34
35    /// Set the maximum number of threads.
36    pub fn with_max_threads(mut self, max_threads: Option<usize>) -> Self {
37        self.max_threads = max_threads;
38        self
39    }
40
41    /// Set the postprocessing pixel threshold.
42    pub fn with_postprocess_pixel_threshold(mut self, threshold: usize) -> Self {
43        self.postprocess_pixel_threshold = threshold;
44        self
45    }
46
47    /// Set the utility operations threshold.
48    pub fn with_utility_threshold(mut self, threshold: usize) -> Self {
49        self.utility_threshold = threshold;
50        self
51    }
52
53    /// Install the global rayon thread pool with the configured number of threads.
54    ///
55    /// This method should be called once at application startup before any parallel
56    /// processing occurs. If `max_threads` is None, this method does nothing and
57    /// rayon will use its default thread pool size.
58    ///
59    /// # Returns
60    ///
61    /// - `Ok(true)` if the thread pool was successfully configured
62    /// - `Ok(false)` if `max_threads` is None (no configuration needed)
63    /// - `Err` if the thread pool has already been initialized
64    ///
65    /// # Example
66    ///
67    /// ```ignore
68    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
69    /// let policy = ParallelPolicy::new().with_max_threads(Some(4));
70    /// policy.install_global_thread_pool()?;
71    /// # Ok(())
72    /// # }
73    /// ```
74    pub fn install_global_thread_pool(&self) -> Result<bool, rayon::ThreadPoolBuildError> {
75        if let Some(num_threads) = self.max_threads {
76            rayon::ThreadPoolBuilder::new()
77                .num_threads(num_threads)
78                .build_global()?;
79            Ok(true)
80        } else {
81            Ok(false)
82        }
83    }
84
85    /// Default value for utility threshold.
86    fn default_utility_threshold() -> usize {
87        4 // Matches DEFAULT_PARALLEL_THRESHOLD from constants.
88    }
89
90    /// Default postprocessing pixel threshold.
91    fn default_postprocess_pixel_threshold() -> usize {
92        8_000
93    }
94}
95
96impl Default for ParallelPolicy {
97    fn default() -> Self {
98        Self {
99            max_threads: None,
100            utility_threshold: Self::default_utility_threshold(),
101            postprocess_pixel_threshold: Self::default_postprocess_pixel_threshold(),
102        }
103    }
104}