use std::path::PathBuf;
use std::time::{Duration, Instant};
#[derive(Debug, Default)]
pub struct IndexStats {
pub files_indexed: usize,
pub files_failed: usize,
pub symbols_found: usize,
pub embeddings_failed: usize,
pub elapsed: Duration,
pub errors: Vec<(PathBuf, String)>,
start_time: Option<Instant>,
}
impl IndexStats {
pub fn new() -> Self {
Self {
start_time: Some(Instant::now()),
..Default::default()
}
}
pub fn stop_timing(&mut self) {
if let Some(start) = self.start_time {
self.elapsed = start.elapsed();
self.start_time = None;
}
}
pub fn add_error(&mut self, path: PathBuf, error: String) {
if self.errors.len() < 100 {
self.errors.push((path, error));
}
self.files_failed += 1;
}
pub fn display(&self) {
println!("\nIndexing Complete:");
println!(" Files indexed: {}", self.files_indexed);
println!(" Files failed: {}", self.files_failed);
println!(" Symbols found: {}", self.symbols_found);
println!(" Time elapsed: {:.2}s", self.elapsed.as_secs_f64());
if self.files_indexed > 0 {
let files_per_sec = self.files_indexed as f64 / self.elapsed.as_secs_f64();
println!(" Performance: {files_per_sec:.0} files/second");
let symbols_per_file = self.symbols_found as f64 / self.files_indexed as f64;
println!(" Average symbols/file: {symbols_per_file:.1}");
}
if self.embeddings_failed > 0 {
println!(
"\nWarning: {} symbols failed embedding generation. Semantic search may be incomplete.",
self.embeddings_failed
);
println!(" Run with --force to regenerate embeddings.");
}
if !self.errors.is_empty() {
println!("\nErrors (showing first {}):", self.errors.len().min(5));
for (path, error) in &self.errors[..5.min(self.errors.len())] {
println!(" {}: {}", path.display(), error);
}
if self.errors.len() > 5 {
println!(" ... and {} more errors", self.errors.len() - 5);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stats_display() {
let mut stats = IndexStats::new();
stats.files_indexed = 100;
stats.files_failed = 2;
stats.symbols_found = 1500;
stats.elapsed = Duration::from_secs(5);
stats.display();
}
#[test]
fn test_error_limiting() {
let mut stats = IndexStats::new();
for i in 0..150 {
stats.add_error(PathBuf::from(format!("file{i}.rs")), format!("Error {i}"));
}
assert_eq!(stats.errors.len(), 100);
assert_eq!(stats.files_failed, 150);
}
}