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    /// let policy = ParallelPolicy::new().with_max_threads(Some(4));
69    /// policy.install_global_thread_pool().expect("Failed to configure thread pool");
70    /// ```
71    pub fn install_global_thread_pool(&self) -> Result<bool, rayon::ThreadPoolBuildError> {
72        if let Some(num_threads) = self.max_threads {
73            rayon::ThreadPoolBuilder::new()
74                .num_threads(num_threads)
75                .build_global()?;
76            Ok(true)
77        } else {
78            Ok(false)
79        }
80    }
81
82    /// Default value for utility threshold.
83    fn default_utility_threshold() -> usize {
84        4 // Matches DEFAULT_PARALLEL_THRESHOLD from constants.
85    }
86
87    /// Default postprocessing pixel threshold.
88    fn default_postprocess_pixel_threshold() -> usize {
89        8_000
90    }
91}
92
93impl Default for ParallelPolicy {
94    fn default() -> Self {
95        Self {
96            max_threads: None,
97            utility_threshold: Self::default_utility_threshold(),
98            postprocess_pixel_threshold: Self::default_postprocess_pixel_threshold(),
99        }
100    }
101}