libperl_macrogen/
source.rs1use std::collections::HashMap;
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
6pub struct FileId(u32);
7
8impl FileId {
9 pub fn as_u32(self) -> u32 {
11 self.0
12 }
13}
14
15#[derive(Debug, Clone, Default, PartialEq, Eq)]
17pub struct SourceLocation {
18 pub file_id: FileId,
19 pub line: u32,
20 pub column: u32,
21}
22
23impl SourceLocation {
24 pub fn new(file_id: FileId, line: u32, column: u32) -> Self {
26 Self {
27 file_id,
28 line,
29 column,
30 }
31 }
32}
33
34#[derive(Debug, Default, Clone)]
36pub struct FileRegistry {
37 paths: Vec<PathBuf>,
38 path_to_id: HashMap<PathBuf, FileId>,
39}
40
41impl FileRegistry {
42 pub fn new() -> Self {
44 Self {
45 paths: Vec::new(),
46 path_to_id: HashMap::new(),
47 }
48 }
49
50 pub fn register(&mut self, path: PathBuf) -> FileId {
52 if let Some(&id) = self.path_to_id.get(&path) {
53 return id;
54 }
55 let id = FileId(self.paths.len() as u32);
56 self.path_to_id.insert(path.clone(), id);
57 self.paths.push(path);
58 id
59 }
60
61 pub fn get_path(&self, id: FileId) -> &Path {
63 &self.paths[id.0 as usize]
64 }
65
66 pub fn try_get_path(&self, id: FileId) -> Option<&Path> {
68 self.paths.get(id.0 as usize).map(|p| p.as_path())
69 }
70
71 pub fn len(&self) -> usize {
73 self.paths.len()
74 }
75
76 pub fn is_empty(&self) -> bool {
78 self.paths.is_empty()
79 }
80
81 pub fn iter(&self) -> impl Iterator<Item = (FileId, &Path)> {
83 self.paths
84 .iter()
85 .enumerate()
86 .map(|(i, p)| (FileId(i as u32), p.as_path()))
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_file_registry_register() {
96 let mut registry = FileRegistry::new();
97 let id1 = registry.register(PathBuf::from("/path/to/file1.c"));
98 let id2 = registry.register(PathBuf::from("/path/to/file2.c"));
99
100 assert_ne!(id1, id2);
101 assert_eq!(registry.get_path(id1), Path::new("/path/to/file1.c"));
102 assert_eq!(registry.get_path(id2), Path::new("/path/to/file2.c"));
103 }
104
105 #[test]
106 fn test_file_registry_same_path() {
107 let mut registry = FileRegistry::new();
108 let id1 = registry.register(PathBuf::from("/path/to/file.c"));
109 let id2 = registry.register(PathBuf::from("/path/to/file.c"));
110
111 assert_eq!(id1, id2);
112 assert_eq!(registry.len(), 1);
113 }
114
115 #[test]
116 fn test_source_location() {
117 let loc = SourceLocation::new(FileId(0), 10, 5);
118 assert_eq!(loc.line, 10);
119 assert_eq!(loc.column, 5);
120 }
121}