1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#[cfg(test)]
#[path = "db_test.rs"]
mod test;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::sync::Arc;
use cairo_lang_utils::Upcast;
use crate::ids::{CrateId, CrateLongId, Directory, FileId, FileLongId};
use crate::span::{FileSummary, TextOffset};
pub const CORELIB_CRATE_NAME: &str = "core";
#[salsa::query_group(FilesDatabase)]
pub trait FilesGroup {
#[salsa::interned]
fn intern_crate(&self, crt: CrateLongId) -> CrateId;
#[salsa::interned]
fn intern_file(&self, file: FileLongId) -> FileId;
#[salsa::input]
fn crate_roots(&self) -> Arc<HashMap<CrateId, Directory>>;
#[salsa::input]
fn file_overrides(&self) -> Arc<HashMap<FileId, Arc<String>>>;
fn crates(&self) -> Vec<CrateId>;
fn crate_root_dir(&self, crate_id: CrateId) -> Option<Directory>;
fn priv_raw_file_content(&self, file_id: FileId) -> Option<Arc<String>>;
fn file_content(&self, file_id: FileId) -> Option<Arc<String>>;
fn file_summary(&self, file_id: FileId) -> Option<Arc<FileSummary>>;
}
pub fn init_files_group(db: &mut (dyn FilesGroup + 'static)) {
db.set_file_overrides(Arc::new(HashMap::new()));
db.set_crate_roots(Arc::new(HashMap::new()));
}
pub fn init_dev_corelib(db: &mut (dyn FilesGroup + 'static), path: PathBuf) {
let core_crate = db.intern_crate(CrateLongId(CORELIB_CRATE_NAME.into()));
let core_root_dir = Directory(path);
db.set_crate_root(core_crate, Some(core_root_dir));
}
impl AsFilesGroupMut for dyn FilesGroup {
fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static) {
self
}
}
pub trait FilesGroupEx: Upcast<dyn FilesGroup> + AsFilesGroupMut {
fn override_file_content(&mut self, file: FileId, content: Option<Arc<String>>) {
let mut overrides = Upcast::upcast(self).file_overrides().as_ref().clone();
match content {
Some(content) => overrides.insert(file, content),
None => overrides.remove(&file),
};
self.as_files_group_mut().set_file_overrides(Arc::new(overrides));
}
fn set_crate_root(&mut self, crt: CrateId, root: Option<Directory>) {
let mut crate_roots = Upcast::upcast(self).crate_roots().as_ref().clone();
match root {
Some(root) => crate_roots.insert(crt, root),
None => crate_roots.remove(&crt),
};
self.as_files_group_mut().set_crate_roots(Arc::new(crate_roots));
}
}
impl<T: Upcast<dyn FilesGroup> + AsFilesGroupMut + ?Sized> FilesGroupEx for T {}
pub trait AsFilesGroupMut {
fn as_files_group_mut(&mut self) -> &mut (dyn FilesGroup + 'static);
}
fn crates(db: &dyn FilesGroup) -> Vec<CrateId> {
db.crate_roots().keys().copied().collect()
}
fn crate_root_dir(db: &dyn FilesGroup, crt: CrateId) -> Option<Directory> {
db.crate_roots().get(&crt).cloned()
}
fn priv_raw_file_content(db: &dyn FilesGroup, file: FileId) -> Option<Arc<String>> {
match db.lookup_intern_file(file) {
FileLongId::OnDisk(path) => match fs::read_to_string(path) {
Ok(content) => Some(Arc::new(content)),
Err(_) => None,
},
FileLongId::Virtual(virt) => Some(virt.content),
}
}
fn file_content(db: &dyn FilesGroup, file: FileId) -> Option<Arc<String>> {
let overrides = db.file_overrides();
overrides.get(&file).cloned().or_else(|| db.priv_raw_file_content(file))
}
fn file_summary(db: &dyn FilesGroup, file: FileId) -> Option<Arc<FileSummary>> {
let content = db.file_content(file)?;
let mut line_offsets = vec![TextOffset(0)];
let mut offset = 0;
for ch in content.chars() {
offset += 1;
if ch == '\n' {
line_offsets.push(TextOffset(offset));
}
}
Some(Arc::new(FileSummary { line_offsets, total_length: offset }))
}