diff options
Diffstat (limited to 'crates/libanalysis/src/db/mod.rs')
-rw-r--r-- | crates/libanalysis/src/db/mod.rs | 196 |
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 @@ | |||
1 | mod queries; | ||
2 | |||
3 | use std::{ | ||
4 | hash::{Hash}, | ||
5 | sync::Arc, | ||
6 | fmt::Debug, | ||
7 | any::Any, | ||
8 | iter, | ||
9 | }; | ||
10 | use im; | ||
11 | use salsa; | ||
12 | use { | ||
13 | FileId, | ||
14 | imp::{FileResolverImp}, | ||
15 | }; | ||
16 | |||
17 | |||
18 | #[derive(Clone, Default)] | ||
19 | pub(crate) struct State { | ||
20 | pub(crate) resolver: FileResolverImp, | ||
21 | pub(crate) file_map: im::HashMap<FileId, Arc<str>>, | ||
22 | } | ||
23 | |||
24 | type Data = Arc<Any + Send + Sync + 'static>; | ||
25 | |||
26 | pub(crate) struct QueryCtx<'a> { | ||
27 | inner: &'a salsa::QueryCtx<State, Data> | ||
28 | } | ||
29 | |||
30 | pub(crate) struct Db { | ||
31 | inner: salsa::Db<State, Data> | ||
32 | } | ||
33 | |||
34 | struct GroundQuery<T, R> { | ||
35 | id: u16, | ||
36 | f: fn(&State, &T) -> R, | ||
37 | h: fn(&R) -> u64, | ||
38 | } | ||
39 | |||
40 | pub(crate) struct Query<T, R> { | ||
41 | pub(crate) id: u16, | ||
42 | pub(crate) f: fn(QueryCtx, &T) -> R, | ||
43 | } | ||
44 | |||
45 | impl 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(¶ms)), | ||
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 | |||
94 | impl<'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(¶ms)), | ||
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(¶ms)), | ||
115 | ); | ||
116 | let res = self.inner.get(query_id, Arc::new(params)); | ||
117 | res.downcast().unwrap() | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn 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 | |||
142 | struct SalsaGroundQuery { | ||
143 | query_type: salsa::QueryTypeId, | ||
144 | f: Box<Fn(&State, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, | ||
145 | } | ||
146 | |||
147 | impl<T, R> From<GroundQuery<T, R>> for SalsaGroundQuery | ||
148 | where | ||
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 | |||
166 | struct SalsaQuery { | ||
167 | query_type: salsa::QueryTypeId, | ||
168 | f: Box<Fn(&salsa::QueryCtx<State, Data>, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, | ||
169 | } | ||
170 | |||
171 | impl<T, R> From<Query<T, R>> for SalsaQuery | ||
172 | where | ||
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 | |||
191 | fn 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 | } | ||