sakurs_core/api/
processor.rs

1//! Main sentence processor implementation
2
3use std::io::Read;
4use std::sync::Arc;
5use std::time::Instant;
6
7use crate::api::{Config, Error, Input, Language, Output};
8use crate::application::{DeltaStackProcessor, ExecutionMode, ProcessorConfig};
9use crate::domain::language::{ConfigurableLanguageRules, LanguageRules};
10
11/// Unified sentence processor with clean API
12pub struct SentenceProcessor {
13    processor: DeltaStackProcessor,
14    config: Config,
15}
16
17impl SentenceProcessor {
18    /// Create a new processor with default configuration
19    pub fn new() -> Self {
20        Self::with_config(Config::default()).expect("Default config should always be valid")
21    }
22
23    /// Create a processor with custom configuration
24    pub fn with_config(config: Config) -> Result<Self, Error> {
25        let language_rules = Self::create_language_rules(&config.language);
26        let processor_config = Self::build_processor_config(&config)?;
27        let processor = DeltaStackProcessor::new(processor_config, language_rules);
28
29        Ok(Self { processor, config })
30    }
31
32    /// Create a processor with custom language rules
33    pub fn with_custom_rules(
34        config: Config,
35        language_rules: Arc<dyn LanguageRules>,
36    ) -> Result<Self, Error> {
37        let processor_config = Self::build_processor_config(&config)?;
38        let processor = DeltaStackProcessor::new(processor_config, language_rules);
39
40        Ok(Self { processor, config })
41    }
42
43    /// Create a processor for a specific language
44    pub fn with_language(lang_code: impl Into<String>) -> Result<Self, Error> {
45        let config = Config::builder().language(lang_code)?.build()?;
46        Self::with_config(config)
47    }
48
49    /// Create language rules based on the language
50    fn create_language_rules(language: &Language) -> Arc<dyn LanguageRules> {
51        match language {
52            Language::English => Arc::new(
53                ConfigurableLanguageRules::from_code("en")
54                    .expect("English configuration should be embedded"),
55            ),
56            Language::Japanese => Arc::new(
57                ConfigurableLanguageRules::from_code("ja")
58                    .expect("Japanese configuration should be embedded"),
59            ),
60        }
61    }
62
63    /// Process input and return sentence boundaries
64    pub fn process(&self, input: Input) -> Result<Output, Error> {
65        let start = Instant::now();
66
67        // Convert input to text
68        let text = input.into_text()?;
69
70        // Determine execution mode based on configuration
71        let mode = if let Some(threads) = self.config.threads {
72            if threads == 1 {
73                ExecutionMode::Sequential
74            } else {
75                ExecutionMode::Parallel {
76                    threads: Some(threads),
77                }
78            }
79        } else {
80            ExecutionMode::Adaptive
81        };
82
83        // Process using the processor
84        let result = self.processor.process(&text, mode)?;
85
86        // Convert to public output format
87        let duration = start.elapsed();
88        Ok(Output::from_delta_stack_result(result, &text, duration))
89    }
90
91    /// Process input from a reader stream
92    pub fn process_stream<R: Read + Send + Sync + 'static>(
93        &self,
94        reader: R,
95    ) -> Result<Output, Error> {
96        self.process(Input::from_reader(reader))
97    }
98
99    /// Get the current configuration
100    pub fn config(&self) -> &Config {
101        &self.config
102    }
103
104    /// Convert public config to internal processor config
105    fn build_processor_config(config: &Config) -> Result<ProcessorConfig, Error> {
106        Ok(ProcessorConfig {
107            chunk_size: config.chunk_size,
108            parallel_threshold: config.parallel_threshold,
109            max_threads: config.threads,
110            overlap_size: config.overlap_size,
111        })
112    }
113}
114
115impl Default for SentenceProcessor {
116    fn default() -> Self {
117        Self::new()
118    }
119}