use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Output {
pub boundaries: Vec<Boundary>,
pub metadata: ProcessingMetadata,
}
#[derive(Debug, Clone)]
pub struct Boundary {
pub offset: usize,
pub char_offset: usize,
pub confidence: f32,
pub context: Option<BoundaryContext>,
}
#[derive(Debug, Clone)]
pub struct BoundaryContext {
pub before: String,
pub after: String,
pub reason: String,
}
#[derive(Debug, Clone)]
pub struct ProcessingMetadata {
pub duration: Duration,
pub strategy_used: String,
pub chunks_processed: usize,
pub memory_peak: usize,
pub stats: ProcessingStats,
}
#[derive(Debug, Clone)]
pub struct ProcessingStats {
pub bytes_processed: usize,
pub chars_processed: usize,
pub sentence_count: usize,
pub avg_sentence_length: f32,
}
impl Output {
pub(crate) fn from_delta_stack_result(
result: crate::application::DeltaStackResult,
text: &str,
duration: Duration,
) -> Self {
let char_boundaries = Self::calculate_char_offsets(text, &result.boundaries);
let boundaries = result
.boundaries
.into_iter()
.zip(char_boundaries)
.map(|(offset, char_offset)| Boundary {
offset,
char_offset,
confidence: 1.0, context: None,
})
.collect::<Vec<_>>();
let sentence_count = boundaries.len();
let avg_sentence_length = if sentence_count > 0 {
text.chars().count() as f32 / sentence_count as f32
} else {
0.0
};
let strategy_used = if result.thread_count > 1 {
format!("parallel ({} threads)", result.thread_count)
} else {
"sequential".to_string()
};
Self {
boundaries,
metadata: ProcessingMetadata {
duration,
strategy_used,
chunks_processed: result.chunk_count,
memory_peak: 0, stats: ProcessingStats {
bytes_processed: text.len(),
chars_processed: text.chars().count(),
sentence_count,
avg_sentence_length,
},
},
}
}
fn calculate_char_offsets(text: &str, byte_offsets: &[usize]) -> Vec<usize> {
let mut char_offsets = Vec::with_capacity(byte_offsets.len());
let mut offsets = byte_offsets.iter().copied().peekable();
let mut char_count = 0;
let mut byte_count = 0;
for ch in text.chars() {
while offsets.peek() == Some(&byte_count) {
char_offsets.push(char_count);
offsets.next();
}
byte_count += ch.len_utf8();
char_count += 1;
}
while offsets.peek() == Some(&byte_count) {
char_offsets.push(char_count);
offsets.next();
}
char_offsets
}
}