joule_common/
source_map.rs1use std::collections::HashMap;
7use std::sync::atomic::{AtomicU32, Ordering};
8
9pub type FileId = u32;
11
12#[derive(Debug, Clone)]
14pub struct FileInfo {
15 pub id: FileId,
17 pub name: String,
19 pub source: String,
21}
22
23#[derive(Debug)]
25pub struct SourceMap {
26 files: HashMap<FileId, FileInfo>,
27 next_id: AtomicU32,
28}
29
30impl SourceMap {
31 pub fn new() -> Self {
33 Self {
34 files: HashMap::new(),
35 next_id: AtomicU32::new(1), }
37 }
38
39 pub fn add_file(&mut self, name: String, source: String) -> FileId {
41 let id = self.next_id.fetch_add(1, Ordering::SeqCst);
42 let info = FileInfo { id, name, source };
43 self.files.insert(id, info);
44 id
45 }
46
47 pub fn get_file(&self, id: FileId) -> Option<&FileInfo> {
49 self.files.get(&id)
50 }
51
52 pub fn files(&self) -> impl Iterator<Item = (&FileId, &FileInfo)> {
54 self.files.iter()
55 }
56
57 pub fn len(&self) -> usize {
59 self.files.len()
60 }
61
62 pub fn is_empty(&self) -> bool {
64 self.files.is_empty()
65 }
66}
67
68impl Default for SourceMap {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_source_map_basic() {
80 let mut map = SourceMap::new();
81 let id = map.add_file("test.joule".to_string(), "fn main() {}".to_string());
82
83 assert_eq!(map.len(), 1);
84 let info = map.get_file(id).unwrap();
85 assert_eq!(info.name, "test.joule");
86 assert_eq!(info.source, "fn main() {}");
87 }
88
89 #[test]
90 fn test_multiple_files() {
91 let mut map = SourceMap::new();
92 let id1 = map.add_file("file1.joule".to_string(), "source1".to_string());
93 let id2 = map.add_file("file2.joule".to_string(), "source2".to_string());
94
95 assert_eq!(map.len(), 2);
96 assert_ne!(id1, id2);
97 assert!(map.get_file(id1).is_some());
98 assert!(map.get_file(id2).is_some());
99 }
100}