use crate::{AbsPath, AbsPathBuf, FileId};
use rustc_hash::FxHashMap;
#[derive(Default)]
pub(crate) struct PathInterner {
path_to_id: FxHashMap<AbsPathBuf, FileId>,
id_to_path: Vec<AbsPathBuf>,
}
impl PathInterner {
pub fn get(&self, path: &AbsPath) -> Option<FileId> {
self.path_to_id.get(path).copied()
}
pub fn intern(&mut self, path: &AbsPath) -> FileId {
if let Some(id) = self.get(path) {
id
} else {
let id = FileId(self.id_to_path.len() as u32);
self.path_to_id.insert(path.to_path_buf(), id);
self.id_to_path.push(path.to_path_buf());
id
}
}
pub fn lookup(&self, id: FileId) -> &AbsPath {
&self.id_to_path[id.0 as usize]
}
}
#[cfg(test)]
mod tests {
use super::PathInterner;
use crate::AbsPathBuf;
use std::convert::TryInto;
use std::path::PathBuf;
#[test]
fn intern() {
let mut interner = PathInterner::default();
let file_path_buf: PathBuf = env!("CARGO_MANIFEST_DIR").into();
let abs_file: AbsPathBuf = file_path_buf.try_into().unwrap();
assert_eq!(interner.get(&abs_file), None);
let file_id = interner.intern(&abs_file);
assert_eq!(interner.get(&abs_file), Some(file_id));
let file_id2 = interner.intern(&abs_file);
assert_eq!(file_id, file_id2);
assert_eq!(&abs_file, interner.lookup(file_id));
}
}