sakurs_core/application/
execution_mode.rs

1//! Execution mode control for text processing
2//!
3//! This module provides a simple and effective way to control how text processing
4//! is executed (sequential vs parallel). We intentionally use this enum-based
5//! approach instead of the Strategy pattern for the following reasons:
6//!
7//! 1. **Simplicity**: The ExecutionMode enum clearly expresses the three modes
8//!    of operation without unnecessary abstraction layers.
9//!
10//! 2. **Performance**: Direct mode selection avoids virtual dispatch overhead
11//!    and keeps the hot path efficient.
12//!
13//! 3. **Maintainability**: All execution logic remains in DeltaStackProcessor,
14//!    making it easier to understand and modify.
15//!
16//! 4. **Sufficient for current needs**: The three modes (Sequential, Parallel,
17//!    and Adaptive) cover all current use cases effectively.
18//!
19//! If future requirements demand more complex execution strategies (e.g.,
20//! streaming, GPU acceleration), we can extend this enum or reconsider the
21//! architecture at that time.
22
23/// Represents the execution mode for text processing
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum ExecutionMode {
26    /// Single-threaded sequential processing
27    Sequential,
28    /// Multi-threaded parallel processing with optional thread count
29    Parallel { threads: Option<usize> },
30    /// Adaptive mode that automatically selects the best strategy
31    Adaptive,
32}
33
34impl ExecutionMode {
35    /// Determines the actual number of threads to use based on the mode and text size
36    pub fn determine_thread_count(&self, text_len: usize) -> usize {
37        match self {
38            ExecutionMode::Sequential => 1,
39            ExecutionMode::Parallel { threads: Some(n) } => *n,
40            ExecutionMode::Parallel { threads: None } | ExecutionMode::Adaptive => {
41                Self::calculate_optimal_threads(text_len)
42            }
43        }
44    }
45
46    /// Calculates the optimal number of threads based on text size
47    /// This preserves the existing heuristics from UnifiedProcessor
48    fn calculate_optimal_threads(text_len: usize) -> usize {
49        const MIN_CHUNK_SIZE: usize = 256 * 1024; // 256KB per thread
50
51        if text_len < MIN_CHUNK_SIZE {
52            1
53        } else {
54            let available_parallelism = std::thread::available_parallelism()
55                .map(|n| n.get())
56                .unwrap_or(1);
57
58            let size_based_threads = (text_len / MIN_CHUNK_SIZE).max(1);
59            size_based_threads.min(available_parallelism)
60        }
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_sequential_mode() {
70        let mode = ExecutionMode::Sequential;
71        assert_eq!(mode.determine_thread_count(1_000_000), 1);
72    }
73
74    #[test]
75    fn test_parallel_mode_with_threads() {
76        let mode = ExecutionMode::Parallel { threads: Some(4) };
77        assert_eq!(mode.determine_thread_count(1_000_000), 4);
78    }
79
80    #[test]
81    fn test_adaptive_mode_small_text() {
82        let mode = ExecutionMode::Adaptive;
83        // Small text should use single thread
84        assert_eq!(mode.determine_thread_count(100_000), 1);
85    }
86
87    #[test]
88    fn test_adaptive_mode_large_text() {
89        let mode = ExecutionMode::Adaptive;
90        // Large text should use multiple threads
91        let thread_count = mode.determine_thread_count(10_000_000);
92        assert!(thread_count > 1);
93    }
94}