From 8c737255ff876fc61f8dc8a7d33252476a4b4c8d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Sep 2018 22:58:36 +0300 Subject: use salsa for new module map --- crates/libanalysis/src/db/mod.rs | 196 +++++++++++++++++++++++++++++++++++ crates/libanalysis/src/db/queries.rs | 43 ++++++++ 2 files changed, 239 insertions(+) create mode 100644 crates/libanalysis/src/db/mod.rs create mode 100644 crates/libanalysis/src/db/queries.rs (limited to 'crates/libanalysis/src/db') 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 @@ +mod queries; + +use std::{ + hash::{Hash}, + sync::Arc, + fmt::Debug, + any::Any, + iter, +}; +use im; +use salsa; +use { + FileId, + imp::{FileResolverImp}, +}; + + +#[derive(Clone, Default)] +pub(crate) struct State { + pub(crate) resolver: FileResolverImp, + pub(crate) file_map: im::HashMap>, +} + +type Data = Arc; + +pub(crate) struct QueryCtx<'a> { + inner: &'a salsa::QueryCtx +} + +pub(crate) struct Db { + inner: salsa::Db +} + +struct GroundQuery { + id: u16, + f: fn(&State, &T) -> R, + h: fn(&R) -> u64, +} + +pub(crate) struct Query { + pub(crate) id: u16, + pub(crate) f: fn(QueryCtx, &T) -> R, +} + +impl Db { + pub(crate) fn new(state: State) -> Db { + Db { inner: salsa::Db::new(query_config(), state) } + } + pub(crate) fn state(&self) -> &State { + self.inner.ground_data() + } + pub(crate) fn with_state( + &self, + new_state: State, + updated_files: &[FileId], + file_set_changed: bool, + ) -> Db { + let mut inv = salsa::Invalidations::new(); + if file_set_changed { + inv.invalidate( + salsa::QueryTypeId(queries::FILE_SET.id), + iter::once(salsa::InputFingerprint(hash(&()))), + ); + } else { + inv.invalidate( + salsa::QueryTypeId(queries::FILE_SET.id), + iter::empty(), + ); + } + inv.invalidate( + salsa::QueryTypeId(queries::FILE_TEXT.id), + updated_files.iter().map(hash).map(salsa::InputFingerprint), + ); + Db { inner: self.inner.with_ground_data(new_state, inv) } + } + pub(crate) fn get(&self, q: Query, params: T) -> (Arc, Vec) + where + T: Hash + Send + Sync + 'static, + R: Send + Sync + 'static, + { + let query_id = salsa::QueryId( + salsa::QueryTypeId(q.id), + salsa::InputFingerprint(hash(¶ms)), + ); + let params = Arc::new(params); + let (res, events) = self.inner.get(query_id, params); + let res = res.downcast().unwrap(); + let events = events.into_iter().map(|it| it.0).collect(); + (res, events) + } + +} + +impl<'a> QueryCtx<'a> { + fn get_g(&self, q: GroundQuery, params: T) -> Arc + where + T: Hash + Send + Sync + 'static, + R: Send + Sync + 'static, + { + let query_id = salsa::QueryId( + salsa::QueryTypeId(q.id), + salsa::InputFingerprint(hash(¶ms)), + ); + let res = self.inner.get(query_id, Arc::new(params)); + res.downcast().unwrap() + } + pub(crate) fn get(&self, q: Query, params: T) -> Arc + where + T: Hash + Send + Sync + 'static, + R: Send + Sync + 'static, + { + let query_id = salsa::QueryId( + salsa::QueryTypeId(q.id), + salsa::InputFingerprint(hash(¶ms)), + ); + let res = self.inner.get(query_id, Arc::new(params)); + res.downcast().unwrap() + } +} + +fn query_config() -> salsa::QueryConfig { + let mut res = salsa::QueryConfig::new(); + let queries: Vec = vec![ + queries::FILE_TEXT.into(), + queries::FILE_SET.into(), + ]; + for q in queries { + res = res.with_ground_query(q.query_type, q.f) + } + let queries: Vec = vec![ + queries::FILE_SYNTAX.into(), + ::module_map_db::MODULE_DESCR.into(), + ::module_map_db::RESOLVE_SUBMODULE.into(), + ::module_map_db::PARENT_MODULE.into(), + ]; + for q in queries { + res = res.with_query(q.query_type, q.f); + } + res +} + +struct SalsaGroundQuery { + query_type: salsa::QueryTypeId, + f: Box (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, +} + +impl From> for SalsaGroundQuery +where + T: Send + Sync + 'static, + R: Send + Sync + 'static, +{ + fn from(q: GroundQuery) -> SalsaGroundQuery + { + SalsaGroundQuery { + query_type: salsa::QueryTypeId(q.id), + f: Box::new(move |state, data| { + let data: &T = data.downcast_ref().unwrap(); + let res = (q.f)(state, data); + let h = (q.h)(&res); + (Arc::new(res), salsa::OutputFingerprint(h)) + }) + } + } +} + +struct SalsaQuery { + query_type: salsa::QueryTypeId, + f: Box, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>, +} + +impl From> for SalsaQuery +where + T: Hash + Send + Sync + 'static, + R: Hash + Send + Sync + 'static, +{ + fn from(q: Query) -> SalsaQuery + { + SalsaQuery { + query_type: salsa::QueryTypeId(q.id), + f: Box::new(move |ctx, data| { + let ctx = QueryCtx { inner: ctx }; + let data: &T = data.downcast_ref().unwrap(); + let res = (q.f)(ctx, data); + let h = hash(&res); + (Arc::new(res), salsa::OutputFingerprint(h)) + }) + } + } +} + +fn hash(x: &T) -> u64 { + use std::hash::Hasher; + let mut hasher = ::std::collections::hash_map::DefaultHasher::new(); + ::std::hash::Hash::hash(x, &mut hasher); + hasher.finish() +} diff --git a/crates/libanalysis/src/db/queries.rs b/crates/libanalysis/src/db/queries.rs new file mode 100644 index 000000000..2d4aac6e9 --- /dev/null +++ b/crates/libanalysis/src/db/queries.rs @@ -0,0 +1,43 @@ +use std::sync::Arc; +use libsyntax2::{File}; +use { + FileId, FileResolverImp, + db::{Query, GroundQuery, QueryCtx, hash}, +}; + + +impl<'a> QueryCtx<'a> { + pub(crate) fn file_set(&self) -> Arc<(Vec, FileResolverImp)> { + self.get_g(FILE_SET, ()) + } + pub(crate) fn file_text(&self, file_id: FileId) -> Arc { + Arc::clone(&*self.get_g(FILE_TEXT, file_id)) + } + pub(crate) fn file_syntax(&self, file_id: FileId) -> File { + (&*self.get(FILE_SYNTAX, file_id)).clone() + } +} + +pub(super) const FILE_TEXT: GroundQuery> = GroundQuery { + id: 10, + f: |state, id| state.file_map[&id].clone(), + h: hash, +}; + +pub(super) const FILE_SET: GroundQuery<(), (Vec, FileResolverImp)> = GroundQuery { + id: 11, + f: |state, &()| { + let files = state.file_map.keys().cloned().collect(); + let resolver = state.resolver.clone(); + (files, resolver) + }, + h: |(files, _)| hash(files), +}; + +pub(super) const FILE_SYNTAX: Query = Query { + id: 20, + f: |ctx, file_id: &FileId| { + let text = ctx.file_text(*file_id); + File::parse(&*text) + } +}; -- cgit v1.2.3