prax_schema/loader/
source.rs1use std::path::{Path, PathBuf};
4
5use serde::{Deserialize, Serialize};
6
7use crate::ast::Span;
8
9#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd, Serialize, Deserialize)]
11pub struct SourceId(pub u32);
12
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
15pub struct SourceLoc {
16 pub source: SourceId,
17 pub span: Span,
18}
19
20impl SourceLoc {
21 pub fn new(source: SourceId, span: Span) -> Self {
22 Self { source, span }
23 }
24}
25
26#[derive(Debug, Clone)]
28pub struct SourceFile {
29 pub path: PathBuf,
30 pub content: String,
31}
32
33#[derive(Debug, Clone, Default)]
37pub struct SourceMap {
38 files: Vec<SourceFile>,
39}
40
41impl SourceMap {
42 pub fn new() -> Self {
43 Self::default()
44 }
45
46 pub fn insert(&mut self, path: impl Into<PathBuf>, content: impl Into<String>) -> SourceId {
48 let id = SourceId(self.files.len() as u32);
49 self.files.push(SourceFile {
50 path: path.into(),
51 content: content.into(),
52 });
53 id
54 }
55
56 pub fn get(&self, id: SourceId) -> Option<&SourceFile> {
57 self.files.get(id.0 as usize)
58 }
59
60 pub fn iter(&self) -> impl Iterator<Item = (SourceId, &SourceFile)> {
61 self.files
62 .iter()
63 .enumerate()
64 .map(|(i, f)| (SourceId(i as u32), f))
65 }
66
67 pub fn len(&self) -> usize {
68 self.files.len()
69 }
70
71 pub fn is_empty(&self) -> bool {
72 self.files.is_empty()
73 }
74
75 pub fn path_of(&self, id: SourceId) -> Option<&Path> {
77 self.get(id).map(|f| f.path.as_path())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn insert_assigns_monotonic_ids() {
87 let mut map = SourceMap::new();
88 let a = map.insert("a.prax", "model A {}");
89 let b = map.insert("b.prax", "model B {}");
90 assert_eq!(a, SourceId(0));
91 assert_eq!(b, SourceId(1));
92 assert_eq!(map.len(), 2);
93 }
94
95 #[test]
96 fn get_returns_inserted_file() {
97 let mut map = SourceMap::new();
98 let id = map.insert("/tmp/x.prax", "content");
99 let f = map.get(id).unwrap();
100 assert_eq!(f.path.to_str().unwrap(), "/tmp/x.prax");
101 assert_eq!(f.content, "content");
102 }
103
104 #[test]
105 fn get_unknown_id_returns_none() {
106 let map = SourceMap::new();
107 assert!(map.get(SourceId(42)).is_none());
108 }
109}