use std::collections::HashMap;
use std::path::{Path, PathBuf};
use crate::graph::CodeGraph;
#[derive(Debug, Clone, Default)]
pub struct PathIndex {
by_path: HashMap<PathBuf, Vec<u64>>,
paths: Vec<PathBuf>,
}
impl PathIndex {
pub fn build(graph: &CodeGraph) -> Self {
let mut by_path: HashMap<PathBuf, Vec<u64>> = HashMap::new();
for unit in graph.units() {
by_path
.entry(unit.file_path.clone())
.or_default()
.push(unit.id);
}
let mut paths: Vec<PathBuf> = by_path.keys().cloned().collect();
paths.sort();
Self { by_path, paths }
}
pub fn lookup(&self, path: &Path) -> &[u64] {
self.by_path.get(path).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn paths(&self) -> &[PathBuf] {
&self.paths
}
pub fn file_count(&self) -> usize {
self.paths.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::CodeGraph;
use crate::types::{CodeUnit, CodeUnitType, Language, Span};
fn make_unit(file_path: &str) -> CodeUnit {
CodeUnit::new(
CodeUnitType::Function,
Language::Rust,
"test_fn".to_string(),
"mod::test_fn".to_string(),
PathBuf::from(file_path),
Span::new(1, 0, 10, 0),
)
}
#[test]
fn test_empty_index() {
let graph = CodeGraph::default();
let index = PathIndex::build(&graph);
assert_eq!(index.file_count(), 0);
assert!(index.paths().is_empty());
assert_eq!(index.lookup(Path::new("src/lib.rs")), &[] as &[u64]);
}
#[test]
fn test_path_lookup() {
let mut graph = CodeGraph::default();
graph.add_unit(make_unit("src/lib.rs"));
graph.add_unit(make_unit("src/lib.rs"));
graph.add_unit(make_unit("src/main.rs"));
let index = PathIndex::build(&graph);
assert_eq!(index.file_count(), 2);
assert_eq!(index.lookup(Path::new("src/lib.rs")), &[0, 1]);
assert_eq!(index.lookup(Path::new("src/main.rs")), &[2]);
assert_eq!(index.lookup(Path::new("src/other.rs")), &[] as &[u64]);
}
#[test]
fn test_paths_sorted() {
let mut graph = CodeGraph::default();
graph.add_unit(make_unit("src/z_file.rs"));
graph.add_unit(make_unit("src/a_file.rs"));
graph.add_unit(make_unit("src/m_file.rs"));
let index = PathIndex::build(&graph);
let paths = index.paths();
assert_eq!(paths.len(), 3);
assert_eq!(paths[0], PathBuf::from("src/a_file.rs"));
assert_eq!(paths[1], PathBuf::from("src/m_file.rs"));
assert_eq!(paths[2], PathBuf::from("src/z_file.rs"));
}
}