aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/db/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libanalysis/src/db/mod.rs')
-rw-r--r--crates/libanalysis/src/db/mod.rs196
1 files changed, 196 insertions, 0 deletions
diff --git a/crates/libanalysis/src/db/mod.rs b/crates/libanalysis/src/db/mod.rs
new file mode 100644
index 000000000..f68aab61c
--- /dev/null
+++ b/crates/libanalysis/src/db/mod.rs
@@ -0,0 +1,196 @@
1mod queries;
2
3use std::{
4 hash::{Hash},
5 sync::Arc,
6 fmt::Debug,
7 any::Any,
8 iter,
9};
10use im;
11use salsa;
12use {
13 FileId,
14 imp::{FileResolverImp},
15};
16
17
18#[derive(Clone, Default)]
19pub(crate) struct State {
20 pub(crate) resolver: FileResolverImp,
21 pub(crate) file_map: im::HashMap<FileId, Arc<str>>,
22}
23
24type Data = Arc<Any + Send + Sync + 'static>;
25
26pub(crate) struct QueryCtx<'a> {
27 inner: &'a salsa::QueryCtx<State, Data>
28}
29
30pub(crate) struct Db {
31 inner: salsa::Db<State, Data>
32}
33
34struct GroundQuery<T, R> {
35 id: u16,
36 f: fn(&State, &T) -> R,
37 h: fn(&R) -> u64,
38}
39
40pub(crate) struct Query<T, R> {
41 pub(crate) id: u16,
42 pub(crate) f: fn(QueryCtx, &T) -> R,
43}
44
45impl Db {
46 pub(crate) fn new(state: State) -> Db {
47 Db { inner: salsa::Db::new(query_config(), state) }
48 }
49 pub(crate) fn state(&self) -> &State {
50 self.inner.ground_data()
51 }
52 pub(crate) fn with_state(
53 &self,
54 new_state: State,
55 updated_files: &[FileId],
56 file_set_changed: bool,
57 ) -> Db {
58 let mut inv = salsa::Invalidations::new();
59 if file_set_changed {
60 inv.invalidate(
61 salsa::QueryTypeId(queries::FILE_SET.id),
62 iter::once(salsa::InputFingerprint(hash(&()))),
63 );
64 } else {
65 inv.invalidate(
66 salsa::QueryTypeId(queries::FILE_SET.id),
67 iter::empty(),
68 );
69 }
70 inv.invalidate(
71 salsa::QueryTypeId(queries::FILE_TEXT.id),
72 updated_files.iter().map(hash).map(salsa::InputFingerprint),
73 );
74 Db { inner: self.inner.with_ground_data(new_state, inv) }
75 }
76 pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> (Arc<R>, Vec<u16>)
77 where
78 T: Hash + Send + Sync + 'static,
79 R: Send + Sync + 'static,
80 {
81 let query_id = salsa::QueryId(
82 salsa::QueryTypeId(q.id),
83 salsa::InputFingerprint(hash(&params)),
84 );
85 let params = Arc::new(params);
86 let (res, events) = self.inner.get(query_id, params);
87 let res = res.downcast().unwrap();
88 let events = events.into_iter().map(|it| it.0).collect();
89 (res, events)
90 }
91
92}
93
94impl<'a> QueryCtx<'a> {
95 fn get_g<T, R>(&self, q: GroundQuery<T, R>, params: T) -> Arc<R>
96 where
97 T: Hash + Send + Sync + 'static,
98 R: Send + Sync + 'static,
99 {
100 let query_id = salsa::QueryId(
101 salsa::QueryTypeId(q.id),
102 salsa::InputFingerprint(hash(&params)),
103 );
104 let res = self.inner.get(query_id, Arc::new(params));
105 res.downcast().unwrap()
106 }
107 pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> Arc<R>
108 where
109 T: Hash + Send + Sync + 'static,
110 R: Send + Sync + 'static,
111 {
112 let query_id = salsa::QueryId(
113 salsa::QueryTypeId(q.id),
114 salsa::InputFingerprint(hash(&params)),
115 );
116 let res = self.inner.get(query_id, Arc::new(params));
117 res.downcast().unwrap()
118 }
119}
120
121fn query_config() -> salsa::QueryConfig<State, Data> {
122 let mut res = salsa::QueryConfig::new();
123 let queries: Vec<SalsaGroundQuery> = vec![
124 queries::FILE_TEXT.into(),
125 queries::FILE_SET.into(),
126 ];
127 for q in queries {
128 res = res.with_ground_query(q.query_type, q.f)
129 }
130 let queries: Vec<SalsaQuery> = vec![
131 queries::FILE_SYNTAX.into(),
132 ::module_map_db::MODULE_DESCR.into(),
133 ::module_map_db::RESOLVE_SUBMODULE.into(),
134 ::module_map_db::PARENT_MODULE.into(),
135 ];
136 for q in queries {
137 res = res.with_query(q.query_type, q.f);
138 }
139 res
140}
141
142struct SalsaGroundQuery {
143 query_type: salsa::QueryTypeId,
144 f: Box<Fn(&State, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>,
145}
146
147impl<T, R> From<GroundQuery<T, R>> for SalsaGroundQuery
148where
149 T: Send + Sync + 'static,
150 R: Send + Sync + 'static,
151{
152 fn from(q: GroundQuery<T, R>) -> SalsaGroundQuery
153 {
154 SalsaGroundQuery {
155 query_type: salsa::QueryTypeId(q.id),
156 f: Box::new(move |state, data| {
157 let data: &T = data.downcast_ref().unwrap();
158 let res = (q.f)(state, data);
159 let h = (q.h)(&res);
160 (Arc::new(res), salsa::OutputFingerprint(h))
161 })
162 }
163 }
164}
165
166struct SalsaQuery {
167 query_type: salsa::QueryTypeId,
168 f: Box<Fn(&salsa::QueryCtx<State, Data>, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>,
169}
170
171impl<T, R> From<Query<T, R>> for SalsaQuery
172where
173 T: Hash + Send + Sync + 'static,
174 R: Hash + Send + Sync + 'static,
175{
176 fn from(q: Query<T, R>) -> SalsaQuery
177 {
178 SalsaQuery {
179 query_type: salsa::QueryTypeId(q.id),
180 f: Box::new(move |ctx, data| {
181 let ctx = QueryCtx { inner: ctx };
182 let data: &T = data.downcast_ref().unwrap();
183 let res = (q.f)(ctx, data);
184 let h = hash(&res);
185 (Arc::new(res), salsa::OutputFingerprint(h))
186 })
187 }
188 }
189}
190
191fn hash<T: ::std::hash::Hash>(x: &T) -> u64 {
192 use std::hash::Hasher;
193 let mut hasher = ::std::collections::hash_map::DefaultHasher::new();
194 ::std::hash::Hash::hash(x, &mut hasher);
195 hasher.finish()
196}