use std::collections::HashMap;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
pub struct FileId(u32);
impl FileId {
pub fn as_u32(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct SourceLocation {
pub file_id: FileId,
pub line: u32,
pub column: u32,
}
impl SourceLocation {
pub fn new(file_id: FileId, line: u32, column: u32) -> Self {
Self {
file_id,
line,
column,
}
}
}
#[derive(Debug, Default, Clone)]
pub struct FileRegistry {
paths: Vec<PathBuf>,
path_to_id: HashMap<PathBuf, FileId>,
}
impl FileRegistry {
pub fn new() -> Self {
Self {
paths: Vec::new(),
path_to_id: HashMap::new(),
}
}
pub fn register(&mut self, path: PathBuf) -> FileId {
if let Some(&id) = self.path_to_id.get(&path) {
return id;
}
let id = FileId(self.paths.len() as u32);
self.path_to_id.insert(path.clone(), id);
self.paths.push(path);
id
}
pub fn get_path(&self, id: FileId) -> &Path {
&self.paths[id.0 as usize]
}
pub fn try_get_path(&self, id: FileId) -> Option<&Path> {
self.paths.get(id.0 as usize).map(|p| p.as_path())
}
pub fn len(&self) -> usize {
self.paths.len()
}
pub fn is_empty(&self) -> bool {
self.paths.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (FileId, &Path)> {
self.paths
.iter()
.enumerate()
.map(|(i, p)| (FileId(i as u32), p.as_path()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_file_registry_register() {
let mut registry = FileRegistry::new();
let id1 = registry.register(PathBuf::from("/path/to/file1.c"));
let id2 = registry.register(PathBuf::from("/path/to/file2.c"));
assert_ne!(id1, id2);
assert_eq!(registry.get_path(id1), Path::new("/path/to/file1.c"));
assert_eq!(registry.get_path(id2), Path::new("/path/to/file2.c"));
}
#[test]
fn test_file_registry_same_path() {
let mut registry = FileRegistry::new();
let id1 = registry.register(PathBuf::from("/path/to/file.c"));
let id2 = registry.register(PathBuf::from("/path/to/file.c"));
assert_eq!(id1, id2);
assert_eq!(registry.len(), 1);
}
#[test]
fn test_source_location() {
let loc = SourceLocation::new(FileId(0), 10, 5);
assert_eq!(loc.line, 10);
assert_eq!(loc.column, 5);
}
}