aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/db.rs')
-rw-r--r--crates/libanalysis/src/db.rs306
1 files changed, 0 insertions, 306 deletions
diff --git a/crates/libanalysis/src/db.rs b/crates/libanalysis/src/db.rs
deleted file mode 100644
index d30e75fe2..000000000
--- a/crates/libanalysis/src/db.rs
+++ /dev/null
@@ -1,306 +0,0 @@
1use std::{
2 hash::{Hash, Hasher},
3 sync::Arc,
4 cell::RefCell,
5 fmt::Debug,
6 any::Any,
7};
8use parking_lot::Mutex;
9use libsyntax2::{File};
10use im;
11use {
12 FileId,
13 imp::{FileResolverImp},
14};
15
16#[derive(Debug)]
17pub(crate) struct DbHost {
18 db: Arc<Db>,
19}
20
21impl DbHost {
22 pub(crate) fn new() -> DbHost {
23 let db = Db {
24 file_resolver: FileResolverImp::default(),
25 files: im::HashMap::new(),
26 cache: Mutex::new(Cache::new())
27 };
28 DbHost { db: Arc::new(db) }
29 }
30 pub(crate) fn change_file(&mut self, file_id: FileId, text: Option<String>) {
31 let db = self.db_mut();
32 match text {
33 None => {
34 db.files.remove(&file_id);
35 }
36 Some(text) => {
37 db.files.insert(file_id, Arc::new(text));
38 }
39 }
40 }
41 pub(crate) fn set_file_resolver(&mut self, file_resolver: FileResolverImp) {
42 let db = self.db_mut();
43 db.file_resolver = file_resolver
44 }
45 pub(crate) fn query_ctx(&self) -> QueryCtx {
46 QueryCtx {
47 db: Arc::clone(&self.db),
48 stack: RefCell::new(Vec::new()),
49 trace: RefCell::new(Vec::new()),
50 }
51 }
52 fn db_mut(&mut self) -> &mut Db {
53 // NB: this "forks" the database
54 let db = Arc::make_mut(&mut self.db);
55 db.cache.get_mut().gen += 1;
56 db
57 }
58}
59
60type QueryInvocationId = (u32, u64);
61type Gen = u64;
62type OutputHash = u64;
63
64fn id<Q: Query>(params: &Q::Params) -> QueryInvocationId {
65 use std::collections::hash_map::DefaultHasher;
66 let mut hasher = DefaultHasher::new();
67 params.hash(&mut hasher);
68 (Q::ID, hasher.finish())
69}
70fn output_hash<Q: Query>(output: &Q::Output) -> OutputHash {
71 use std::collections::hash_map::DefaultHasher;
72 let mut hasher = DefaultHasher::new();
73 output.hash(&mut hasher);
74 hasher.finish()
75}
76
77#[derive(Debug)]
78pub(crate) struct Db {
79 file_resolver: FileResolverImp,
80 files: im::HashMap<FileId, Arc<String>>,
81 cache: Mutex<Cache>,
82}
83
84impl Clone for Db {
85 fn clone(&self) -> Db {
86 Db {
87 file_resolver: self.file_resolver.clone(),
88 files: self.files.clone(),
89 cache: Mutex::new(Cache::new()),
90 }
91 }
92}
93
94type QueryDeps = Vec<(QueryInvocationId, Arc<Any>, OutputHash)>;
95
96#[derive(Default, Debug)]
97pub(crate) struct Cache {
98 gen: Gen,
99 green: im::HashMap<QueryInvocationId, (Gen, OutputHash)>,
100 deps: im::HashMap<QueryInvocationId, QueryDeps>,
101 results: im::HashMap<QueryInvocationId, Arc<Any>>,
102}
103
104
105#[allow(type_alias_bounds)]
106pub(crate) type QueryCache<Q: Query> = im::HashMap<
107 <Q as Query>::Params,
108 <Q as Query>::Output
109>;
110
111impl Cache {
112 fn new() -> Cache {
113 Default::default()
114 }
115
116 fn get_result<Q: Query>(&self, id: QueryInvocationId) -> Q::Output
117 where
118 Q::Output: Clone
119 {
120 let res = &self.results[&id];
121 let res = res.downcast_ref::<Q::Output>().unwrap();
122 res.clone()
123 }
124}
125
126pub(crate) struct QueryCtx {
127 db: Arc<Db>,
128 stack: RefCell<Vec<(QueryInvocationId, QueryDeps)>>,
129 pub(crate) trace: RefCell<Vec<TraceEvent>>,
130}
131
132#[derive(Clone, Copy, Debug)]
133pub(crate) struct TraceEvent {
134 pub(crate) query_id: u32,
135 pub(crate) kind: TraceEventKind
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq)]
139pub(crate) enum TraceEventKind {
140 Start, Evaluating, Finish
141}
142
143impl QueryCtx {
144 pub(crate) fn get<Q: Get>(&self, params: &Q::Params) -> Q::Output {
145 let me = id::<Q>(params);
146 self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Start });
147 let res = Q::get(self, params);
148 self.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Finish });
149 {
150 let mut stack = self.stack.borrow_mut();
151 if let Some((_, ref mut deps)) = stack.last_mut() {
152 let params = Arc::new(params.clone());
153 deps.push((me, params, output_hash::<Q>(&res)));
154 }
155 }
156
157 res
158 }
159 fn trace(&self, event: TraceEvent) {
160 self.trace.borrow_mut().push(event)
161 }
162}
163
164pub(crate) trait Query {
165 const ID: u32;
166 type Params: Hash + Eq + Debug + Clone + Any + 'static;
167 type Output: Hash + Debug + Any + 'static;
168}
169
170pub(crate) trait Get: Query {
171 fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output;
172}
173
174impl<Q: Eval> Get for Q
175where
176 Q::Params: Clone,
177 Q::Output: Clone,
178{
179 fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output {
180 if let Some(res) = try_reuse::<Q>(ctx, params) {
181 return res;
182 }
183
184 let me = id::<Q>(params);
185 ctx.trace(TraceEvent { query_id: Q::ID, kind: TraceEventKind::Evaluating });
186 ctx.stack.borrow_mut().push((me, Vec::new()));
187 let res = Self::eval(ctx, params);
188 let (also_me, deps) = ctx.stack.borrow_mut().pop().unwrap();
189 assert_eq!(also_me, me);
190 let mut cache = ctx.db.cache.lock();
191 cache.deps.insert(me, deps);
192 let gen = cache.gen;
193 let output_hash = output_hash::<Q>(&res);
194 let id = id::<Q>(params);
195 cache.green.insert(id, (gen, output_hash));
196 cache.results.insert(me, Arc::new(res.clone()));
197 res
198 }
199}
200
201fn try_reuse<Q: Eval>(ctx: &QueryCtx, params: &Q::Params) -> Option<Q::Output>
202where
203 Q::Params: Clone,
204 Q::Output: Clone,
205{
206 let id = id::<Q>(params);
207 let mut cache = ctx.db.cache.lock();
208 let curr_gen = cache.gen;
209 let old_hash = match *cache.green.get(&id)? {
210 (gen, _) if gen == curr_gen => {
211 return Some(cache.get_result::<Q>(id));
212 }
213 (_, hash) => hash,
214 };
215 let deps_are_fresh = cache.deps[&id]
216 .iter()
217 .all(|&(dep_id, _, dep_hash)| {
218 match cache.green.get(&dep_id) {
219 //TODO: store the value of parameters, and re-execute the query
220 Some((gen, hash)) if gen == &curr_gen && hash == &dep_hash => true,
221 _ => false,
222 }
223 });
224 if !deps_are_fresh {
225 return None;
226 }
227 cache.green.insert(id, (curr_gen, old_hash));
228 Some(cache.get_result::<Q>(id))
229}
230
231pub(crate) trait Eval: Query
232where
233 Self::Params: Clone,
234 Self::Output: Clone,
235{
236 fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output;
237}
238
239#[derive(Debug)]
240pub(crate) struct DbFiles {
241 db: Arc<Db>,
242}
243
244impl Hash for DbFiles {
245 fn hash<H: Hasher>(&self, hasher: &mut H) {
246 self.db.cache.lock().gen.hash(hasher)
247 }
248}
249
250impl DbFiles {
251 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item=FileId> + 'a {
252 self.db.files.keys().cloned()
253 }
254 pub(crate) fn file_resolver(&self) -> FileResolverImp {
255 self.db.file_resolver.clone()
256 }
257}
258
259pub(crate) enum Files {}
260impl Query for Files {
261 const ID: u32 = 1;
262 type Params = ();
263 type Output = DbFiles;
264}
265impl Get for Files {
266 fn get(ctx: &QueryCtx, params: &()) -> DbFiles {
267 let res = DbFiles { db: Arc::clone(&ctx.db) };
268 let id = id::<Self>(params);
269 let hash = output_hash::<Self>(&res);
270 let mut cache = ctx.db.cache.lock();
271 let gen = cache.gen;
272 cache.green.insert(id, (gen, hash));
273 res
274 }
275}
276
277enum FileText {}
278impl Query for FileText {
279 const ID: u32 = 10;
280 type Params = FileId;
281 type Output = Arc<String>;
282}
283impl Get for FileText {
284 fn get(ctx: &QueryCtx, file_id: &FileId) -> Arc<String> {
285 let res = ctx.db.files[file_id].clone();
286 let id = id::<Self>(file_id);
287 let hash = output_hash::<Self>(&res);
288 let mut cache = ctx.db.cache.lock();
289 let gen = cache.gen;
290 cache.green.insert(id, (gen, hash));
291 res
292 }
293}
294
295pub(crate) enum FileSyntax {}
296impl Query for FileSyntax {
297 const ID: u32 = 20;
298 type Params = FileId;
299 type Output = File;
300}
301impl Eval for FileSyntax {
302 fn eval(ctx: &QueryCtx, file_id: &FileId) -> File {
303 let text = ctx.get::<FileText>(file_id);
304 File::parse(&text)
305 }
306}