diff options
author | Aleksey Kladov <[email protected]> | 2018-09-15 15:21:47 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-09-15 22:00:05 +0100 |
commit | d59413c895e7b49ed2ad01be35871e417a57a43c (patch) | |
tree | b0615655a8344c8d079be8c7b1b1e05445c43d7e | |
parent | 0d7b1e442d1449a48e0b73b3db6ea270520ea039 (diff) |
yet another db api
-rw-r--r-- | crates/libanalysis/src/db/imp.rs | 155 | ||||
-rw-r--r-- | crates/libanalysis/src/db/mod.rs | 214 | ||||
-rw-r--r-- | crates/libanalysis/src/db/queries.rs | 43 | ||||
-rw-r--r-- | crates/libanalysis/src/module_map_db/mod.rs | 108 | ||||
-rw-r--r-- | crates/salsa/src/lib.rs | 12 |
5 files changed, 274 insertions, 258 deletions
diff --git a/crates/libanalysis/src/db/imp.rs b/crates/libanalysis/src/db/imp.rs new file mode 100644 index 000000000..1b4ee5cf3 --- /dev/null +++ b/crates/libanalysis/src/db/imp.rs | |||
@@ -0,0 +1,155 @@ | |||
1 | use std::{ | ||
2 | sync::Arc, | ||
3 | any::Any, | ||
4 | hash::{Hash, Hasher}, | ||
5 | collections::hash_map::{DefaultHasher, HashMap}, | ||
6 | iter, | ||
7 | }; | ||
8 | use salsa; | ||
9 | use {FileId, imp::FileResolverImp}; | ||
10 | use super::{State, Query, QueryCtx}; | ||
11 | |||
12 | pub(super) type Data = Arc<Any + Send + Sync + 'static>; | ||
13 | |||
14 | #[derive(Debug)] | ||
15 | pub(super) struct Db { | ||
16 | names: Arc<HashMap<salsa::QueryTypeId, &'static str>>, | ||
17 | pub(super) imp: salsa::Db<State, Data>, | ||
18 | } | ||
19 | |||
20 | impl Db { | ||
21 | pub(super) fn new(mut reg: QueryRegistry) -> Db { | ||
22 | let config = reg.config.take().unwrap(); | ||
23 | Db { | ||
24 | names: Arc::new(reg.names), | ||
25 | imp: salsa::Db::new(config, State::default()) | ||
26 | } | ||
27 | } | ||
28 | pub(crate) fn with_changes(&self, new_state: State, changed_files: &[FileId], resolver_changed: bool) -> Db { | ||
29 | let names = self.names.clone(); | ||
30 | let mut invalidations = salsa::Invalidations::new(); | ||
31 | invalidations.invalidate(FILE_TEXT, changed_files.iter().map(hash).map(salsa::InputFingerprint)); | ||
32 | if resolver_changed { | ||
33 | invalidations.invalidate(FILE_SET, iter::once(salsa::InputFingerprint(hash(&())))); | ||
34 | } else { | ||
35 | invalidations.invalidate(FILE_SET, iter::empty()); | ||
36 | } | ||
37 | let imp = self.imp.with_ground_data( | ||
38 | new_state, | ||
39 | invalidations, | ||
40 | ); | ||
41 | Db { names, imp } | ||
42 | } | ||
43 | pub(super) fn extract_trace(&self, ctx: &salsa::QueryCtx<State, Data>) -> Vec<&'static str> { | ||
44 | ctx.trace().into_iter().map(|it| self.names[&it]).collect() | ||
45 | } | ||
46 | } | ||
47 | |||
48 | pub(crate) trait EvalQuery { | ||
49 | type Params; | ||
50 | type Output; | ||
51 | fn query_type(&self) -> salsa::QueryTypeId; | ||
52 | fn f(&self) -> salsa::QueryFn<State, Data>; | ||
53 | fn get(&self, &QueryCtx, Self::Params) -> Arc<Self::Output>; | ||
54 | } | ||
55 | |||
56 | impl<T, R> EvalQuery for Query<T, R> | ||
57 | where | ||
58 | T: Hash + Send + Sync + 'static, | ||
59 | R: Hash + Send + Sync + 'static, | ||
60 | { | ||
61 | type Params = T; | ||
62 | type Output = R; | ||
63 | fn query_type(&self) -> salsa::QueryTypeId { | ||
64 | salsa::QueryTypeId(self.0) | ||
65 | } | ||
66 | fn f(&self) -> salsa::QueryFn<State, Data> { | ||
67 | let f = self.1; | ||
68 | Box::new(move |ctx, data| { | ||
69 | let ctx = QueryCtx { imp: ctx }; | ||
70 | let data: &T = data.downcast_ref().unwrap(); | ||
71 | let res = f(ctx, data); | ||
72 | let h = hash(&res); | ||
73 | (Arc::new(res), salsa::OutputFingerprint(h)) | ||
74 | }) | ||
75 | } | ||
76 | fn get(&self, ctx: &QueryCtx, params: Self::Params) -> Arc<Self::Output> { | ||
77 | let query_id = salsa::QueryId( | ||
78 | self.query_type(), | ||
79 | salsa::InputFingerprint(hash(¶ms)), | ||
80 | ); | ||
81 | let res = ctx.imp.get(query_id, Arc::new(params)); | ||
82 | res.downcast().unwrap() | ||
83 | } | ||
84 | } | ||
85 | |||
86 | pub(super) struct QueryRegistry { | ||
87 | config: Option<salsa::QueryConfig<State, Data>>, | ||
88 | names: HashMap<salsa::QueryTypeId, &'static str>, | ||
89 | } | ||
90 | |||
91 | impl QueryRegistry { | ||
92 | pub(super) fn new() -> QueryRegistry { | ||
93 | let mut config = salsa::QueryConfig::<State, Data>::new(); | ||
94 | config = config.with_ground_query( | ||
95 | FILE_TEXT, Box::new(|state, params| { | ||
96 | let file_id: &FileId = params.downcast_ref().unwrap(); | ||
97 | let res = state.file_map[file_id].clone(); | ||
98 | let fingerprint = salsa::OutputFingerprint(hash(&res)); | ||
99 | (res, fingerprint) | ||
100 | }) | ||
101 | ); | ||
102 | config = config.with_ground_query( | ||
103 | FILE_SET, Box::new(|state, _params| { | ||
104 | let file_ids: Vec<FileId> = state.file_map.keys().cloned().collect(); | ||
105 | let hash = hash(&file_ids); | ||
106 | let file_resolver = state.file_resolver.clone(); | ||
107 | let res = (file_ids, file_resolver); | ||
108 | let fingerprint = salsa::OutputFingerprint(hash); | ||
109 | (Arc::new(res), fingerprint) | ||
110 | }) | ||
111 | ); | ||
112 | let mut names = HashMap::new(); | ||
113 | names.insert(FILE_TEXT, "FILE_TEXT"); | ||
114 | names.insert(FILE_SET, "FILE_SET"); | ||
115 | QueryRegistry { config: Some(config), names } | ||
116 | } | ||
117 | pub(super) fn add<Q: EvalQuery>(&mut self, q: Q, name: &'static str) { | ||
118 | let id = q.query_type(); | ||
119 | let prev = self.names.insert(id, name); | ||
120 | assert!(prev.is_none(), "duplicate query: {:?}", id); | ||
121 | let config = self.config.take().unwrap(); | ||
122 | let config = config.with_query(id, q.f()); | ||
123 | self.config= Some(config); | ||
124 | } | ||
125 | pub(super) fn finish(mut self) -> salsa::QueryConfig<State, Data> { | ||
126 | self.config.take().unwrap() | ||
127 | } | ||
128 | } | ||
129 | |||
130 | fn hash<T: Hash>(x: &T) -> u64 { | ||
131 | let mut hasher = DefaultHasher::new(); | ||
132 | x.hash(&mut hasher); | ||
133 | hasher.finish() | ||
134 | } | ||
135 | |||
136 | const FILE_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(0); | ||
137 | pub(super) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> { | ||
138 | let query_id = salsa::QueryId( | ||
139 | FILE_TEXT, | ||
140 | salsa::InputFingerprint(hash(&file_id)), | ||
141 | ); | ||
142 | let res = ctx.imp.get(query_id, Arc::new(file_id)); | ||
143 | res.downcast().unwrap() | ||
144 | } | ||
145 | |||
146 | const FILE_SET: salsa::QueryTypeId = salsa::QueryTypeId(1); | ||
147 | pub(super) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> { | ||
148 | let query_id = salsa::QueryId( | ||
149 | FILE_SET, | ||
150 | salsa::InputFingerprint(hash(&())), | ||
151 | ); | ||
152 | let res = ctx.imp.get(query_id, Arc::new(())); | ||
153 | res.downcast().unwrap() | ||
154 | } | ||
155 | |||
diff --git a/crates/libanalysis/src/db/mod.rs b/crates/libanalysis/src/db/mod.rs index 38ba40273..a775b5f75 100644 --- a/crates/libanalysis/src/db/mod.rs +++ b/crates/libanalysis/src/db/mod.rs | |||
@@ -1,195 +1,99 @@ | |||
1 | mod queries; | 1 | mod imp; |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | hash::{Hash}, | ||
5 | sync::Arc, | 4 | sync::Arc, |
6 | fmt::Debug, | ||
7 | any::Any, | ||
8 | iter, | ||
9 | }; | 5 | }; |
10 | use im; | 6 | use im; |
11 | use salsa; | 7 | use salsa; |
12 | use { | 8 | use {FileId, imp::FileResolverImp}; |
13 | FileId, | ||
14 | imp::{FileResolverImp}, | ||
15 | }; | ||
16 | |||
17 | 9 | ||
18 | #[derive(Clone, Default)] | 10 | #[derive(Debug, Default, Clone)] |
19 | pub(crate) struct State { | 11 | pub(crate) struct State { |
20 | pub(crate) resolver: FileResolverImp, | 12 | pub(crate) file_map: im::HashMap<FileId, Arc<String>>, |
21 | pub(crate) file_map: im::HashMap<FileId, Arc<str>>, | 13 | pub(crate) file_resolver: FileResolverImp |
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 | } | 14 | } |
29 | 15 | ||
16 | #[derive(Debug)] | ||
30 | pub(crate) struct Db { | 17 | pub(crate) struct Db { |
31 | inner: salsa::Db<State, Data> | 18 | imp: imp::Db, |
32 | } | 19 | } |
33 | 20 | ||
34 | struct GroundQuery<T, R> { | 21 | #[derive(Clone, Copy)] |
35 | id: u16, | 22 | pub(crate) struct QueryCtx<'a> { |
36 | f: fn(&State, &T) -> R, | 23 | imp: &'a salsa::QueryCtx<State, imp::Data>, |
37 | h: fn(&R) -> u64, | ||
38 | } | 24 | } |
39 | 25 | ||
40 | pub(crate) struct Query<T, R> { | 26 | pub(crate) struct Query<T, R>(pub(crate) u16, pub(crate) fn(QueryCtx, &T) -> R); |
41 | pub(crate) id: u16, | 27 | |
42 | pub(crate) f: fn(QueryCtx, &T) -> R, | 28 | pub(crate) struct QueryRegistry { |
29 | imp: imp::QueryRegistry, | ||
43 | } | 30 | } |
44 | 31 | ||
45 | impl Db { | 32 | impl Db { |
46 | pub(crate) fn new() -> Db { | 33 | pub(crate) fn new() -> Db { |
47 | let state = Default::default(); | 34 | let reg = QueryRegistry::new(); |
48 | Db { inner: salsa::Db::new(query_config(), state) } | 35 | Db { imp: imp::Db::new(reg.imp) } |
49 | } | 36 | } |
50 | pub(crate) fn state(&self) -> &State { | 37 | pub(crate) fn state(&self) -> &State { |
51 | self.inner.ground_data() | 38 | self.imp.imp.ground_data() |
52 | } | 39 | } |
53 | pub(crate) fn with_state( | 40 | pub(crate) fn with_changes(&self, new_state: State, changed_files: &[FileId], resolver_changed: bool) -> Db { |
54 | &self, | 41 | Db { imp: self.imp.with_changes(new_state, changed_files, resolver_changed) } |
55 | new_state: State, | ||
56 | updated_files: &[FileId], | ||
57 | file_set_changed: bool, | ||
58 | ) -> Db { | ||
59 | let mut inv = salsa::Invalidations::new(); | ||
60 | if file_set_changed { | ||
61 | inv.invalidate( | ||
62 | salsa::QueryTypeId(queries::FILE_SET.id), | ||
63 | iter::once(salsa::InputFingerprint(hash(&()))), | ||
64 | ); | ||
65 | } else { | ||
66 | inv.invalidate( | ||
67 | salsa::QueryTypeId(queries::FILE_SET.id), | ||
68 | iter::empty(), | ||
69 | ); | ||
70 | } | ||
71 | inv.invalidate( | ||
72 | salsa::QueryTypeId(queries::FILE_TEXT.id), | ||
73 | updated_files.iter().map(hash).map(salsa::InputFingerprint), | ||
74 | ); | ||
75 | Db { inner: self.inner.with_ground_data(new_state, inv) } | ||
76 | } | 42 | } |
77 | pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> (Arc<R>, Vec<u16>) | 43 | pub(crate) fn make_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> R { |
78 | where | 44 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; |
79 | T: Hash + Send + Sync + 'static, | 45 | f(ctx) |
80 | R: Send + Sync + 'static, | 46 | } |
81 | { | 47 | pub(crate) fn trace_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> (R, Vec<&'static str>) { |
82 | let query_id = salsa::QueryId( | 48 | let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() }; |
83 | salsa::QueryTypeId(q.id), | 49 | let res = f(ctx); |
84 | salsa::InputFingerprint(hash(¶ms)), | 50 | let trace = self.imp.extract_trace(ctx.imp); |
85 | ); | 51 | (res, trace) |
86 | let params = Arc::new(params); | ||
87 | let (res, events) = self.inner.get(query_id, params); | ||
88 | let res = res.downcast().unwrap(); | ||
89 | let events = events.into_iter().map(|it| it.0).collect(); | ||
90 | (res, events) | ||
91 | } | 52 | } |
92 | |||
93 | } | 53 | } |
94 | 54 | ||
95 | impl<'a> QueryCtx<'a> { | 55 | impl<'a> QueryCtx<'a> { |
96 | fn get_g<T, R>(&self, q: GroundQuery<T, R>, params: T) -> Arc<R> | 56 | pub(crate) fn get<Q: imp::EvalQuery>(&self, q: Q, params: Q::Params) -> Arc<Q::Output> { |
97 | where | 57 | q.get(self, params) |
98 | T: Hash + Send + Sync + 'static, | ||
99 | R: Send + Sync + 'static, | ||
100 | { | ||
101 | let query_id = salsa::QueryId( | ||
102 | salsa::QueryTypeId(q.id), | ||
103 | salsa::InputFingerprint(hash(¶ms)), | ||
104 | ); | ||
105 | let res = self.inner.get(query_id, Arc::new(params)); | ||
106 | res.downcast().unwrap() | ||
107 | } | ||
108 | pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> Arc<R> | ||
109 | where | ||
110 | T: Hash + Send + Sync + 'static, | ||
111 | R: Send + Sync + 'static, | ||
112 | { | ||
113 | let query_id = salsa::QueryId( | ||
114 | salsa::QueryTypeId(q.id), | ||
115 | salsa::InputFingerprint(hash(¶ms)), | ||
116 | ); | ||
117 | let res = self.inner.get(query_id, Arc::new(params)); | ||
118 | res.downcast().unwrap() | ||
119 | } | 58 | } |
120 | } | 59 | } |
121 | 60 | ||
122 | fn query_config() -> salsa::QueryConfig<State, Data> { | 61 | pub(crate) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> { |
123 | let mut res = salsa::QueryConfig::new(); | 62 | imp::file_text(ctx, file_id) |
124 | let queries: Vec<BoxedGroundQuery> = vec![ | ||
125 | queries::FILE_TEXT.into(), | ||
126 | queries::FILE_SET.into(), | ||
127 | ]; | ||
128 | for q in queries { | ||
129 | res = res.with_ground_query(q.query_type, q.f) | ||
130 | } | ||
131 | let mut queries: Vec<BoxedQuery> = vec![ | ||
132 | queries::FILE_SYNTAX.into(), | ||
133 | ]; | ||
134 | ::module_map_db::queries(&mut queries); | ||
135 | for q in queries { | ||
136 | res = res.with_query(q.query_type, q.f); | ||
137 | } | ||
138 | res | ||
139 | } | 63 | } |
140 | 64 | ||
141 | struct BoxedGroundQuery { | 65 | pub(crate) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> { |
142 | query_type: salsa::QueryTypeId, | 66 | imp::file_set(ctx) |
143 | f: Box<Fn(&State, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, | ||
144 | } | 67 | } |
68 | pub(crate) use self::queries::file_syntax; | ||
145 | 69 | ||
146 | impl<T, R> From<GroundQuery<T, R>> for BoxedGroundQuery | 70 | mod queries { |
147 | where | 71 | use libsyntax2::File; |
148 | T: Send + Sync + 'static, | 72 | use {FileId}; |
149 | R: Send + Sync + 'static, | 73 | use super::{Query, QueryCtx, QueryRegistry, file_text}; |
150 | { | ||
151 | fn from(q: GroundQuery<T, R>) -> BoxedGroundQuery | ||
152 | { | ||
153 | BoxedGroundQuery { | ||
154 | query_type: salsa::QueryTypeId(q.id), | ||
155 | f: Box::new(move |state, data| { | ||
156 | let data: &T = data.downcast_ref().unwrap(); | ||
157 | let res = (q.f)(state, data); | ||
158 | let h = (q.h)(&res); | ||
159 | (Arc::new(res), salsa::OutputFingerprint(h)) | ||
160 | }) | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | 74 | ||
165 | pub(crate) struct BoxedQuery { | 75 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { |
166 | query_type: salsa::QueryTypeId, | 76 | reg.add(FILE_SYNTAX, "FILE_SYNTAX") |
167 | f: Box<Fn(&salsa::QueryCtx<State, Data>, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, | 77 | } |
168 | } | ||
169 | 78 | ||
170 | impl<T, R> From<Query<T, R>> for BoxedQuery | 79 | pub(crate) fn file_syntax(ctx: QueryCtx, file_id: FileId) -> File { |
171 | where | 80 | (&*ctx.get(FILE_SYNTAX, file_id)).clone() |
172 | T: Hash + Send + Sync + 'static, | ||
173 | R: Hash + Send + Sync + 'static, | ||
174 | { | ||
175 | fn from(q: Query<T, R>) -> BoxedQuery | ||
176 | { | ||
177 | BoxedQuery { | ||
178 | query_type: salsa::QueryTypeId(q.id), | ||
179 | f: Box::new(move |ctx, data| { | ||
180 | let ctx = QueryCtx { inner: ctx }; | ||
181 | let data: &T = data.downcast_ref().unwrap(); | ||
182 | let res = (q.f)(ctx, data); | ||
183 | let h = hash(&res); | ||
184 | (Arc::new(res), salsa::OutputFingerprint(h)) | ||
185 | }) | ||
186 | } | ||
187 | } | 81 | } |
82 | |||
83 | pub(super) const FILE_SYNTAX: Query<FileId, File> = Query(16, |ctx, file_id: &FileId| { | ||
84 | let text = file_text(ctx, *file_id); | ||
85 | File::parse(&*text) | ||
86 | }); | ||
188 | } | 87 | } |
189 | 88 | ||
190 | fn hash<T: ::std::hash::Hash>(x: &T) -> u64 { | 89 | impl QueryRegistry { |
191 | use std::hash::Hasher; | 90 | fn new() -> QueryRegistry { |
192 | let mut hasher = ::std::collections::hash_map::DefaultHasher::new(); | 91 | let mut reg = QueryRegistry { imp: imp::QueryRegistry::new() }; |
193 | ::std::hash::Hash::hash(x, &mut hasher); | 92 | queries::register_queries(&mut reg); |
194 | hasher.finish() | 93 | ::module_map_db::register_queries(&mut reg); |
94 | reg | ||
95 | } | ||
96 | pub(crate) fn add<Q: imp::EvalQuery>(&mut self, q: Q, name: &'static str) { | ||
97 | self.imp.add(q, name) | ||
98 | } | ||
195 | } | 99 | } |
diff --git a/crates/libanalysis/src/db/queries.rs b/crates/libanalysis/src/db/queries.rs deleted file mode 100644 index 2d4aac6e9..000000000 --- a/crates/libanalysis/src/db/queries.rs +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | use std::sync::Arc; | ||
2 | use libsyntax2::{File}; | ||
3 | use { | ||
4 | FileId, FileResolverImp, | ||
5 | db::{Query, GroundQuery, QueryCtx, hash}, | ||
6 | }; | ||
7 | |||
8 | |||
9 | impl<'a> QueryCtx<'a> { | ||
10 | pub(crate) fn file_set(&self) -> Arc<(Vec<FileId>, FileResolverImp)> { | ||
11 | self.get_g(FILE_SET, ()) | ||
12 | } | ||
13 | pub(crate) fn file_text(&self, file_id: FileId) -> Arc<str> { | ||
14 | Arc::clone(&*self.get_g(FILE_TEXT, file_id)) | ||
15 | } | ||
16 | pub(crate) fn file_syntax(&self, file_id: FileId) -> File { | ||
17 | (&*self.get(FILE_SYNTAX, file_id)).clone() | ||
18 | } | ||
19 | } | ||
20 | |||
21 | pub(super) const FILE_TEXT: GroundQuery<FileId, Arc<str>> = GroundQuery { | ||
22 | id: 10, | ||
23 | f: |state, id| state.file_map[&id].clone(), | ||
24 | h: hash, | ||
25 | }; | ||
26 | |||
27 | pub(super) const FILE_SET: GroundQuery<(), (Vec<FileId>, FileResolverImp)> = GroundQuery { | ||
28 | id: 11, | ||
29 | f: |state, &()| { | ||
30 | let files = state.file_map.keys().cloned().collect(); | ||
31 | let resolver = state.resolver.clone(); | ||
32 | (files, resolver) | ||
33 | }, | ||
34 | h: |(files, _)| hash(files), | ||
35 | }; | ||
36 | |||
37 | pub(super) const FILE_SYNTAX: Query<FileId, File> = Query { | ||
38 | id: 20, | ||
39 | f: |ctx, file_id: &FileId| { | ||
40 | let text = ctx.file_text(*file_id); | ||
41 | File::parse(&*text) | ||
42 | } | ||
43 | }; | ||
diff --git a/crates/libanalysis/src/module_map_db/mod.rs b/crates/libanalysis/src/module_map_db/mod.rs index 02ac06c5f..5560e4a34 100644 --- a/crates/libanalysis/src/module_map_db/mod.rs +++ b/crates/libanalysis/src/module_map_db/mod.rs | |||
@@ -4,15 +4,16 @@ use std::sync::Arc; | |||
4 | use { | 4 | use { |
5 | FileId, | 5 | FileId, |
6 | db::{ | 6 | db::{ |
7 | BoxedQuery, Query, QueryCtx | 7 | Query, QueryRegistry, QueryCtx, |
8 | file_syntax, file_set | ||
8 | }, | 9 | }, |
9 | module_map::resolve_submodule, | 10 | module_map::resolve_submodule, |
10 | }; | 11 | }; |
11 | 12 | ||
12 | pub(crate) fn queries(acc: &mut Vec<BoxedQuery>) { | 13 | pub(crate) fn register_queries(reg: &mut QueryRegistry) { |
13 | acc.push(MODULE_DESCR.into()); | 14 | reg.add(MODULE_DESCR, "MODULE_DESCR"); |
14 | acc.push(RESOLVE_SUBMODULE.into()); | 15 | reg.add(RESOLVE_SUBMODULE, "RESOLVE_SUBMODULE"); |
15 | acc.push(PARENT_MODULE.into()); | 16 | reg.add(PARENT_MODULE, "PARENT_MODULE"); |
16 | } | 17 | } |
17 | 18 | ||
18 | impl<'a> QueryCtx<'a> { | 19 | impl<'a> QueryCtx<'a> { |
@@ -24,41 +25,32 @@ impl<'a> QueryCtx<'a> { | |||
24 | } | 25 | } |
25 | } | 26 | } |
26 | 27 | ||
27 | pub(crate) const MODULE_DESCR: Query<FileId, descr::ModuleDescr> = Query { | 28 | const MODULE_DESCR: Query<FileId, descr::ModuleDescr> = Query(30, |ctx, &file_id| { |
28 | id: 30, | 29 | let file = file_syntax(ctx, file_id); |
29 | f: |ctx, &file_id| { | 30 | descr::ModuleDescr::new(file.ast()) |
30 | let file = ctx.file_syntax(file_id); | 31 | }); |
31 | descr::ModuleDescr::new(file.ast()) | 32 | |
32 | } | 33 | const RESOLVE_SUBMODULE: Query<(FileId, descr::Submodule), Vec<FileId>> = Query(31, |ctx, params| { |
33 | }; | 34 | let files = file_set(ctx); |
34 | 35 | resolve_submodule(params.0, ¶ms.1.name, &files.1).0 | |
35 | pub(crate) const RESOLVE_SUBMODULE: Query<(FileId, descr::Submodule), Vec<FileId>> = Query { | 36 | }); |
36 | id: 31, | 37 | |
37 | f: |ctx, params| { | 38 | const PARENT_MODULE: Query<FileId, Vec<FileId>> = Query(40, |ctx, file_id| { |
38 | let files = ctx.file_set(); | 39 | let files = file_set(ctx); |
39 | resolve_submodule(params.0, ¶ms.1.name, &files.1).0 | 40 | let res = files.0.iter() |
40 | } | 41 | .map(|&parent_id| (parent_id, ctx.module_descr(parent_id))) |
41 | }; | 42 | .filter(|(parent_id, descr)| { |
42 | 43 | descr.submodules.iter() | |
43 | pub(crate) const PARENT_MODULE: Query<FileId, Vec<FileId>> = Query { | 44 | .any(|subm| { |
44 | id: 40, | 45 | ctx.resolve_submodule(*parent_id, subm.clone()) |
45 | f: |ctx, file_id| { | 46 | .iter() |
46 | let files = ctx.file_set(); | 47 | .any(|it| it == file_id) |
47 | let res = files.0.iter() | 48 | }) |
48 | .map(|&parent_id| (parent_id, ctx.module_descr(parent_id))) | 49 | }) |
49 | .filter(|(parent_id, descr)| { | 50 | .map(|(id, _)| id) |
50 | descr.submodules.iter() | 51 | .collect(); |
51 | .any(|subm| { | 52 | res |
52 | ctx.resolve_submodule(*parent_id, subm.clone()) | 53 | }); |
53 | .iter() | ||
54 | .any(|it| it == file_id) | ||
55 | }) | ||
56 | }) | ||
57 | .map(|(id, _)| id) | ||
58 | .collect(); | ||
59 | res | ||
60 | } | ||
61 | }; | ||
62 | 54 | ||
63 | #[cfg(test)] | 55 | #[cfg(test)] |
64 | mod tests { | 56 | mod tests { |
@@ -107,34 +99,36 @@ mod tests { | |||
107 | self.next_file_id += 1; | 99 | self.next_file_id += 1; |
108 | self.fm.insert(file_id, RelativePathBuf::from(&path[1..])); | 100 | self.fm.insert(file_id, RelativePathBuf::from(&path[1..])); |
109 | let mut new_state = self.db.state().clone(); | 101 | let mut new_state = self.db.state().clone(); |
110 | new_state.file_map.insert(file_id, text.to_string().into_boxed_str().into()); | 102 | new_state.file_map.insert(file_id, Arc::new(text.to_string())); |
111 | new_state.resolver = FileResolverImp::new( | 103 | new_state.file_resolver = FileResolverImp::new( |
112 | Arc::new(FileMap(self.fm.clone())) | 104 | Arc::new(FileMap(self.fm.clone())) |
113 | ); | 105 | ); |
114 | self.db = self.db.with_state(new_state, &[file_id], true); | 106 | self.db = self.db.with_changes(new_state, &[file_id], true); |
115 | file_id | 107 | file_id |
116 | } | 108 | } |
117 | fn remove_file(&mut self, file_id: FileId) { | 109 | fn remove_file(&mut self, file_id: FileId) { |
118 | self.fm.remove(&file_id); | 110 | self.fm.remove(&file_id); |
119 | let mut new_state = self.db.state().clone(); | 111 | let mut new_state = self.db.state().clone(); |
120 | new_state.file_map.remove(&file_id); | 112 | new_state.file_map.remove(&file_id); |
121 | new_state.resolver = FileResolverImp::new( | 113 | new_state.file_resolver = FileResolverImp::new( |
122 | Arc::new(FileMap(self.fm.clone())) | 114 | Arc::new(FileMap(self.fm.clone())) |
123 | ); | 115 | ); |
124 | self.db = self.db.with_state(new_state, &[file_id], true); | 116 | self.db = self.db.with_changes(new_state, &[file_id], true); |
125 | } | 117 | } |
126 | fn change_file(&mut self, file_id: FileId, new_text: &str) { | 118 | fn change_file(&mut self, file_id: FileId, new_text: &str) { |
127 | let mut new_state = self.db.state().clone(); | 119 | let mut new_state = self.db.state().clone(); |
128 | new_state.file_map.insert(file_id, new_text.to_string().into_boxed_str().into()); | 120 | new_state.file_map.insert(file_id, Arc::new(new_text.to_string())); |
129 | self.db = self.db.with_state(new_state, &[file_id], false); | 121 | self.db = self.db.with_changes(new_state, &[file_id], false); |
130 | } | 122 | } |
131 | fn check_parent_modules( | 123 | fn check_parent_modules( |
132 | &self, | 124 | &self, |
133 | file_id: FileId, | 125 | file_id: FileId, |
134 | expected: &[FileId], | 126 | expected: &[FileId], |
135 | queries: &[(u16, u64)] | 127 | queries: &[(&'static str, u64)] |
136 | ) { | 128 | ) { |
137 | let (actual, events) = self.db.get(PARENT_MODULE, file_id); | 129 | let (actual, events) = self.db.trace_query(|ctx| { |
130 | ctx.get(PARENT_MODULE, file_id) | ||
131 | }); | ||
138 | assert_eq!(actual.as_slice(), expected); | 132 | assert_eq!(actual.as_slice(), expected); |
139 | let mut counts = HashMap::new(); | 133 | let mut counts = HashMap::new(); |
140 | events.into_iter() | 134 | events.into_iter() |
@@ -156,25 +150,25 @@ mod tests { | |||
156 | fn test_parent_module() { | 150 | fn test_parent_module() { |
157 | let mut f = Fixture::new(); | 151 | let mut f = Fixture::new(); |
158 | let foo = f.add_file("/foo.rs", ""); | 152 | let foo = f.add_file("/foo.rs", ""); |
159 | f.check_parent_modules(foo, &[], &[(MODULE_DESCR.id, 1)]); | 153 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); |
160 | 154 | ||
161 | let lib = f.add_file("/lib.rs", "mod foo;"); | 155 | let lib = f.add_file("/lib.rs", "mod foo;"); |
162 | f.check_parent_modules(foo, &[lib], &[(MODULE_DESCR.id, 1)]); | 156 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
163 | f.check_parent_modules(foo, &[lib], &[(MODULE_DESCR.id, 0)]); | 157 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 0)]); |
164 | 158 | ||
165 | f.change_file(lib, ""); | 159 | f.change_file(lib, ""); |
166 | f.check_parent_modules(foo, &[], &[(MODULE_DESCR.id, 1)]); | 160 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); |
167 | 161 | ||
168 | f.change_file(lib, "mod foo;"); | 162 | f.change_file(lib, "mod foo;"); |
169 | f.check_parent_modules(foo, &[lib], &[(MODULE_DESCR.id, 1)]); | 163 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
170 | 164 | ||
171 | f.change_file(lib, "mod bar;"); | 165 | f.change_file(lib, "mod bar;"); |
172 | f.check_parent_modules(foo, &[], &[(MODULE_DESCR.id, 1)]); | 166 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 1)]); |
173 | 167 | ||
174 | f.change_file(lib, "mod foo;"); | 168 | f.change_file(lib, "mod foo;"); |
175 | f.check_parent_modules(foo, &[lib], &[(MODULE_DESCR.id, 1)]); | 169 | f.check_parent_modules(foo, &[lib], &[("MODULE_DESCR", 1)]); |
176 | 170 | ||
177 | f.remove_file(lib); | 171 | f.remove_file(lib); |
178 | f.check_parent_modules(foo, &[], &[(MODULE_DESCR.id, 0)]); | 172 | f.check_parent_modules(foo, &[], &[("MODULE_DESCR", 0)]); |
179 | } | 173 | } |
180 | } | 174 | } |
diff --git a/crates/salsa/src/lib.rs b/crates/salsa/src/lib.rs index 75815e8bd..35deed374 100644 --- a/crates/salsa/src/lib.rs +++ b/crates/salsa/src/lib.rs | |||
@@ -8,8 +8,8 @@ use std::{ | |||
8 | }; | 8 | }; |
9 | use parking_lot::Mutex; | 9 | use parking_lot::Mutex; |
10 | 10 | ||
11 | type GroundQueryFn<T, D> = Box<Fn(&T, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>; | 11 | pub type GroundQueryFn<T, D> = Box<Fn(&T, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>; |
12 | type QueryFn<T, D> = Box<Fn(&QueryCtx<T, D>, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>; | 12 | pub type QueryFn<T, D> = Box<Fn(&QueryCtx<T, D>, &D) -> (D, OutputFingerprint) + Send + Sync + 'static>; |
13 | 13 | ||
14 | #[derive(Debug)] | 14 | #[derive(Debug)] |
15 | pub struct Db<T, D> { | 15 | pub struct Db<T, D> { |
@@ -118,6 +118,9 @@ where | |||
118 | self.record_dep(query_id, output_fingerprint); | 118 | self.record_dep(query_id, output_fingerprint); |
119 | res | 119 | res |
120 | } | 120 | } |
121 | pub fn trace(&self) -> Vec<QueryTypeId> { | ||
122 | ::std::mem::replace(&mut *self.executed.borrow_mut(), Vec::new()) | ||
123 | } | ||
121 | 124 | ||
122 | fn get_inner( | 125 | fn get_inner( |
123 | &self, | 126 | &self, |
@@ -261,12 +264,15 @@ where | |||
261 | query_config: Arc::clone(&self.query_config) | 264 | query_config: Arc::clone(&self.query_config) |
262 | } | 265 | } |
263 | } | 266 | } |
267 | pub fn query_ctx(&self) -> QueryCtx<T, D> { | ||
268 | QueryCtx::new(self) | ||
269 | } | ||
264 | pub fn get( | 270 | pub fn get( |
265 | &self, | 271 | &self, |
266 | query_id: QueryId, | 272 | query_id: QueryId, |
267 | params: D, | 273 | params: D, |
268 | ) -> (D, Vec<QueryTypeId>) { | 274 | ) -> (D, Vec<QueryTypeId>) { |
269 | let ctx = QueryCtx::new(self); | 275 | let ctx = self.query_ctx(); |
270 | let res = ctx.get(query_id, params.into()); | 276 | let res = ctx.get(query_id, params.into()); |
271 | let executed = ::std::mem::replace(&mut *ctx.executed.borrow_mut(), Vec::new()); | 277 | let executed = ::std::mem::replace(&mut *ctx.executed.borrow_mut(), Vec::new()); |
272 | (res, executed) | 278 | (res, executed) |