use path_slash::PathExt;
use salsa::Durability;
use crate::Db;
use crate::system::{SystemPath, SystemPathBuf};
#[salsa::input(debug, heap_size=ruff_memory_usage::heap_size)]
pub struct FileRoot {
#[returns(deref)]
pub path: Box<SystemPath>,
#[returns(copy)]
pub kind_at_time_of_creation: FileRootKind,
}
impl FileRoot {
pub(crate) fn durability(self, db: &dyn Db) -> salsa::Durability {
self.kind_at_time_of_creation(db).durability()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
pub enum FileRootKind {
Project,
SearchPath,
}
impl FileRootKind {
const fn durability(self) -> Durability {
match self {
FileRootKind::Project => Durability::LOW,
FileRootKind::SearchPath => Durability::HIGH,
}
}
}
#[derive(Default)]
pub(super) struct FileRoots {
by_path: matchit::Router<FileRoot>,
}
impl FileRoots {
pub(super) fn try_add(
&mut self,
db: &dyn Db,
path: SystemPathBuf,
kind: FileRootKind,
) -> FileRoot {
let normalized_path = path.as_std_path().to_slash().unwrap();
if let Ok(existing) = self.by_path.at(&normalized_path) {
if existing.value.path(db) == &*path {
return *existing.value;
}
}
tracing::debug!("Adding new file root '{path}' of kind {kind:?}");
let mut route = normalized_path.replace('{', "{{").replace('}', "}}");
let root = FileRoot::builder(path.into(), kind)
.durability(Durability::NEVER_CHANGE)
.new(db);
self.by_path.insert(route.clone(), root).unwrap();
if !route.ends_with("/") {
route.push('/');
}
route.push_str("{*filepath}");
self.by_path.insert(route, root).unwrap();
root
}
pub(super) fn at(&self, path: &SystemPath) -> Option<FileRoot> {
let normalized_path = path.as_std_path().to_slash().unwrap();
let entry = self.by_path.at(&normalized_path).ok()?;
Some(*entry.value)
}
}