use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, OnceLock, RwLock};
use crate::graph_cache::cache;
use crate::graph_cache::UnifiedGraph;
type Registry = RwLock<HashMap<PathBuf, Arc<UnifiedGraph>>>;
static REGISTRY: OnceLock<Registry> = OnceLock::new();
fn registry() -> &'static Registry {
REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
pub fn get_or_init(root: &Path) -> std::io::Result<Arc<UnifiedGraph>> {
let key = root_for(root);
{
let r = registry().read().unwrap();
if let Some(g) = r.get(&key) {
return Ok(g.clone());
}
}
let graph = cache::load_or_build(&key, false)?;
let arc = Arc::new(graph);
registry().write().unwrap().insert(key, arc.clone());
Ok(arc)
}
pub fn rebuild(root: &Path) -> std::io::Result<Arc<UnifiedGraph>> {
let key = root_for(root);
let graph = cache::load_or_build(&key, true)?;
let arc = Arc::new(graph);
registry().write().unwrap().insert(key, arc.clone());
Ok(arc)
}
pub fn promote_calls<F>(root: &Path, build: F) -> std::io::Result<Arc<UnifiedGraph>>
where
F: FnOnce(&UnifiedGraph) -> crate::calls::graph::CallGraph,
{
let current = get_or_init(root)?;
if current.calls.is_some() {
return Ok(current);
}
let calls = build(¤t);
let promoted = Arc::new(UnifiedGraph {
deps: current.deps.clone(),
calls: Some(calls),
});
let key = root_for(root);
registry().write().unwrap().insert(key.clone(), promoted.clone());
if let Ok(records) = cache::collect_file_records(&key) {
let _ = cache::save(&key, &promoted, &records);
}
Ok(promoted)
}
#[allow(dead_code)]
pub fn forget(root: &Path) {
let key = root_for(root);
registry().write().unwrap().remove(&key);
}
pub fn root_for(root: &Path) -> PathBuf {
root.canonicalize().unwrap_or_else(|_| root.to_path_buf())
}
#[allow(dead_code)]
pub fn with_root<R, F: FnOnce(&UnifiedGraph) -> R>(root: &Path, f: F) -> std::io::Result<R> {
let g = get_or_init(root)?;
Ok(f(&g))
}