diff options
Diffstat (limited to 'crates/libanalysis/src/db.rs')
-rw-r--r-- | crates/libanalysis/src/db.rs | 306 |
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 @@ | |||
1 | use std::{ | ||
2 | hash::{Hash, Hasher}, | ||
3 | sync::Arc, | ||
4 | cell::RefCell, | ||
5 | fmt::Debug, | ||
6 | any::Any, | ||
7 | }; | ||
8 | use parking_lot::Mutex; | ||
9 | use libsyntax2::{File}; | ||
10 | use im; | ||
11 | use { | ||
12 | FileId, | ||
13 | imp::{FileResolverImp}, | ||
14 | }; | ||
15 | |||
16 | #[derive(Debug)] | ||
17 | pub(crate) struct DbHost { | ||
18 | db: Arc<Db>, | ||
19 | } | ||
20 | |||
21 | impl 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 | |||
60 | type QueryInvocationId = (u32, u64); | ||
61 | type Gen = u64; | ||
62 | type OutputHash = u64; | ||
63 | |||
64 | fn 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 | } | ||
70 | fn 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)] | ||
78 | pub(crate) struct Db { | ||
79 | file_resolver: FileResolverImp, | ||
80 | files: im::HashMap<FileId, Arc<String>>, | ||
81 | cache: Mutex<Cache>, | ||
82 | } | ||
83 | |||
84 | impl 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 | |||
94 | type QueryDeps = Vec<(QueryInvocationId, Arc<Any>, OutputHash)>; | ||
95 | |||
96 | #[derive(Default, Debug)] | ||
97 | pub(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)] | ||
106 | pub(crate) type QueryCache<Q: Query> = im::HashMap< | ||
107 | <Q as Query>::Params, | ||
108 | <Q as Query>::Output | ||
109 | >; | ||
110 | |||
111 | impl 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 | |||
126 | pub(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)] | ||
133 | pub(crate) struct TraceEvent { | ||
134 | pub(crate) query_id: u32, | ||
135 | pub(crate) kind: TraceEventKind | ||
136 | } | ||
137 | |||
138 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
139 | pub(crate) enum TraceEventKind { | ||
140 | Start, Evaluating, Finish | ||
141 | } | ||
142 | |||
143 | impl 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 | |||
164 | pub(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 | |||
170 | pub(crate) trait Get: Query { | ||
171 | fn get(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; | ||
172 | } | ||
173 | |||
174 | impl<Q: Eval> Get for Q | ||
175 | where | ||
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 | |||
201 | fn try_reuse<Q: Eval>(ctx: &QueryCtx, params: &Q::Params) -> Option<Q::Output> | ||
202 | where | ||
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 | |||
231 | pub(crate) trait Eval: Query | ||
232 | where | ||
233 | Self::Params: Clone, | ||
234 | Self::Output: Clone, | ||
235 | { | ||
236 | fn eval(ctx: &QueryCtx, params: &Self::Params) -> Self::Output; | ||
237 | } | ||
238 | |||
239 | #[derive(Debug)] | ||
240 | pub(crate) struct DbFiles { | ||
241 | db: Arc<Db>, | ||
242 | } | ||
243 | |||
244 | impl Hash for DbFiles { | ||
245 | fn hash<H: Hasher>(&self, hasher: &mut H) { | ||
246 | self.db.cache.lock().gen.hash(hasher) | ||
247 | } | ||
248 | } | ||
249 | |||
250 | impl 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 | |||
259 | pub(crate) enum Files {} | ||
260 | impl Query for Files { | ||
261 | const ID: u32 = 1; | ||
262 | type Params = (); | ||
263 | type Output = DbFiles; | ||
264 | } | ||
265 | impl 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 | |||
277 | enum FileText {} | ||
278 | impl Query for FileText { | ||
279 | const ID: u32 = 10; | ||
280 | type Params = FileId; | ||
281 | type Output = Arc<String>; | ||
282 | } | ||
283 | impl 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 | |||
295 | pub(crate) enum FileSyntax {} | ||
296 | impl Query for FileSyntax { | ||
297 | const ID: u32 = 20; | ||
298 | type Params = FileId; | ||
299 | type Output = File; | ||
300 | } | ||
301 | impl 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 | } | ||