aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_batch/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_batch/src/lib.rs')
-rw-r--r--crates/ra_batch/src/lib.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
new file mode 100644
index 000000000..837fff4dc
--- /dev/null
+++ b/crates/ra_batch/src/lib.rs
@@ -0,0 +1,151 @@
1use std::sync::Arc;
2use std::path::Path;
3use std::collections::HashSet;
4
5use rustc_hash::FxHashMap;
6
7use ra_db::{
8 CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa,
9};
10use ra_hir::{db, HirInterner};
11use ra_project_model::ProjectWorkspace;
12use ra_vfs::{Vfs, VfsChange};
13
14type Result<T> = std::result::Result<T, failure::Error>;
15
16#[salsa::database(
17 ra_db::SourceDatabaseStorage,
18 db::HirDatabaseStorage,
19 db::PersistentHirDatabaseStorage
20)]
21#[derive(Debug)]
22pub struct BatchDatabase {
23 runtime: salsa::Runtime<BatchDatabase>,
24 interner: Arc<HirInterner>,
25}
26
27impl salsa::Database for BatchDatabase {
28 fn salsa_runtime(&self) -> &salsa::Runtime<BatchDatabase> {
29 &self.runtime
30 }
31}
32
33impl AsRef<HirInterner> for BatchDatabase {
34 fn as_ref(&self) -> &HirInterner {
35 &self.interner
36 }
37}
38
39fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
40 FileId(f.0.into())
41}
42fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
43 SourceRootId(r.0.into())
44}
45
46impl BatchDatabase {
47 pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase {
48 let mut db =
49 BatchDatabase { runtime: salsa::Runtime::default(), interner: Default::default() };
50 db.set_crate_graph(Arc::new(crate_graph));
51
52 // wait until Vfs has loaded all roots
53 let receiver = vfs.task_receiver().clone();
54 let mut roots_loaded = HashSet::new();
55 for task in receiver {
56 vfs.handle_task(task);
57 let mut done = false;
58 for change in vfs.commit_changes() {
59 match change {
60 VfsChange::AddRoot { root, files } => {
61 let source_root_id = vfs_root_to_id(root);
62 log::debug!(
63 "loaded source root {:?} with path {:?}",
64 source_root_id,
65 vfs.root2path(root)
66 );
67 let mut file_map = FxHashMap::default();
68 for (vfs_file, path, text) in files {
69 let file_id = vfs_file_to_id(vfs_file);
70 db.set_file_text(file_id, text);
71 db.set_file_relative_path(file_id, path.clone());
72 db.set_file_source_root(file_id, source_root_id);
73 file_map.insert(path, file_id);
74 }
75 let source_root = SourceRoot { files: file_map };
76 db.set_source_root(source_root_id, Arc::new(source_root));
77 roots_loaded.insert(source_root_id);
78 if roots_loaded.len() == vfs.num_roots() {
79 done = true;
80 }
81 }
82 VfsChange::AddFile { .. }
83 | VfsChange::RemoveFile { .. }
84 | VfsChange::ChangeFile { .. } => {
85 // We just need the first scan, so just ignore these
86 }
87 }
88 }
89 if done {
90 break;
91 }
92 }
93
94 db
95 }
96
97 pub fn load_cargo(root: impl AsRef<Path>) -> Result<(BatchDatabase, Vec<SourceRootId>)> {
98 let root = root.as_ref().canonicalize()?;
99 let ws = ProjectWorkspace::discover(root.as_ref())?;
100 let mut roots = Vec::new();
101 roots.push(root.clone());
102 for pkg in ws.cargo.packages() {
103 roots.push(pkg.root(&ws.cargo).to_path_buf());
104 }
105 for krate in ws.sysroot.crates() {
106 roots.push(krate.root_dir(&ws.sysroot).to_path_buf())
107 }
108 let (mut vfs, roots) = Vfs::new(roots);
109 let mut load = |path: &Path| {
110 let vfs_file = vfs.load(path);
111 log::debug!("vfs file {:?} -> {:?}", path, vfs_file);
112 vfs_file.map(vfs_file_to_id)
113 };
114 let crate_graph = ws.to_crate_graph(&mut load);
115 log::debug!("crate graph: {:?}", crate_graph);
116
117 let local_roots = roots
118 .into_iter()
119 .filter(|r| vfs.root2path(*r).starts_with(&root))
120 .map(vfs_root_to_id)
121 .collect();
122
123 let db = BatchDatabase::load(crate_graph, &mut vfs);
124 let _ = vfs.shutdown();
125 Ok((db, local_roots))
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use ra_hir::Crate;
132 use super::*;
133
134 #[test]
135 fn test_loading_rust_analyzer() {
136 let mut path = std::env::current_exe().unwrap();
137 while !path.join("Cargo.toml").is_file() {
138 path = path.parent().unwrap().to_owned();
139 }
140 let (db, roots) = BatchDatabase::load_cargo(path).unwrap();
141 let mut num_crates = 0;
142 for root in roots {
143 for _krate in Crate::source_root_crates(&db, root) {
144 num_crates += 1;
145 }
146 }
147
148 // RA has quite a few crates, but the exact count doesn't matter
149 assert!(num_crates > 20);
150 }
151}