yet another db api

This commit is contained in:
Aleksey Kladov
2018-09-15 17:21:47 +03:00
parent 0d7b1e442d
commit d59413c895
5 changed files with 276 additions and 260 deletions

View File

@@ -1,195 +1,99 @@
mod queries;
mod imp;
use std::{
hash::{Hash},
sync::Arc,
fmt::Debug,
any::Any,
iter,
};
use im;
use salsa;
use {
FileId,
imp::{FileResolverImp},
};
use {FileId, imp::FileResolverImp};
#[derive(Clone, Default)]
#[derive(Debug, Default, Clone)]
pub(crate) struct State {
pub(crate) resolver: FileResolverImp,
pub(crate) file_map: im::HashMap<FileId, Arc<str>>,
}
type Data = Arc<Any + Send + Sync + 'static>;
pub(crate) struct QueryCtx<'a> {
inner: &'a salsa::QueryCtx<State, Data>
pub(crate) file_map: im::HashMap<FileId, Arc<String>>,
pub(crate) file_resolver: FileResolverImp
}
#[derive(Debug)]
pub(crate) struct Db {
inner: salsa::Db<State, Data>
imp: imp::Db,
}
struct GroundQuery<T, R> {
id: u16,
f: fn(&State, &T) -> R,
h: fn(&R) -> u64,
#[derive(Clone, Copy)]
pub(crate) struct QueryCtx<'a> {
imp: &'a salsa::QueryCtx<State, imp::Data>,
}
pub(crate) struct Query<T, R> {
pub(crate) id: u16,
pub(crate) f: fn(QueryCtx, &T) -> R,
pub(crate) struct Query<T, R>(pub(crate) u16, pub(crate) fn(QueryCtx, &T) -> R);
pub(crate) struct QueryRegistry {
imp: imp::QueryRegistry,
}
impl Db {
pub(crate) fn new() -> Db {
let state = Default::default();
Db { inner: salsa::Db::new(query_config(), state) }
let reg = QueryRegistry::new();
Db { imp: imp::Db::new(reg.imp) }
}
pub(crate) fn state(&self) -> &State {
self.inner.ground_data()
self.imp.imp.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 with_changes(&self, new_state: State, changed_files: &[FileId], resolver_changed: bool) -> Db {
Db { imp: self.imp.with_changes(new_state, changed_files, resolver_changed) }
}
pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> (Arc<R>, Vec<u16>)
where
T: Hash + Send + Sync + 'static,
R: Send + Sync + 'static,
{
let query_id = salsa::QueryId(
salsa::QueryTypeId(q.id),
salsa::InputFingerprint(hash(&params)),
);
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)
pub(crate) fn make_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> R {
let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() };
f(ctx)
}
pub(crate) fn trace_query<F: FnOnce(QueryCtx) -> R, R>(&self, f: F) -> (R, Vec<&'static str>) {
let ctx = QueryCtx { imp: &self.imp.imp.query_ctx() };
let res = f(ctx);
let trace = self.imp.extract_trace(ctx.imp);
(res, trace)
}
}
impl<'a> QueryCtx<'a> {
fn get_g<T, R>(&self, q: GroundQuery<T, R>, params: T) -> Arc<R>
where
T: Hash + Send + Sync + 'static,
R: Send + Sync + 'static,
{
let query_id = salsa::QueryId(
salsa::QueryTypeId(q.id),
salsa::InputFingerprint(hash(&params)),
);
let res = self.inner.get(query_id, Arc::new(params));
res.downcast().unwrap()
}
pub(crate) fn get<T, R>(&self, q: Query<T, R>, params: T) -> Arc<R>
where
T: Hash + Send + Sync + 'static,
R: Send + Sync + 'static,
{
let query_id = salsa::QueryId(
salsa::QueryTypeId(q.id),
salsa::InputFingerprint(hash(&params)),
);
let res = self.inner.get(query_id, Arc::new(params));
res.downcast().unwrap()
pub(crate) fn get<Q: imp::EvalQuery>(&self, q: Q, params: Q::Params) -> Arc<Q::Output> {
q.get(self, params)
}
}
fn query_config() -> salsa::QueryConfig<State, Data> {
let mut res = salsa::QueryConfig::new();
let queries: Vec<BoxedGroundQuery> = vec![
queries::FILE_TEXT.into(),
queries::FILE_SET.into(),
];
for q in queries {
res = res.with_ground_query(q.query_type, q.f)
}
let mut queries: Vec<BoxedQuery> = vec![
queries::FILE_SYNTAX.into(),
];
::module_map_db::queries(&mut queries);
for q in queries {
res = res.with_query(q.query_type, q.f);
}
res
pub(crate) fn file_text(ctx: QueryCtx, file_id: FileId) -> Arc<String> {
imp::file_text(ctx, file_id)
}
struct BoxedGroundQuery {
query_type: salsa::QueryTypeId,
f: Box<Fn(&State, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>,
pub(crate) fn file_set(ctx: QueryCtx) -> Arc<(Vec<FileId>, FileResolverImp)> {
imp::file_set(ctx)
}
pub(crate) use self::queries::file_syntax;
mod queries {
use libsyntax2::File;
use {FileId};
use super::{Query, QueryCtx, QueryRegistry, file_text};
pub(crate) fn register_queries(reg: &mut QueryRegistry) {
reg.add(FILE_SYNTAX, "FILE_SYNTAX")
}
pub(crate) fn file_syntax(ctx: QueryCtx, file_id: FileId) -> File {
(&*ctx.get(FILE_SYNTAX, file_id)).clone()
}
pub(super) const FILE_SYNTAX: Query<FileId, File> = Query(16, |ctx, file_id: &FileId| {
let text = file_text(ctx, *file_id);
File::parse(&*text)
});
}
impl<T, R> From<GroundQuery<T, R>> for BoxedGroundQuery
where
T: Send + Sync + 'static,
R: Send + Sync + 'static,
{
fn from(q: GroundQuery<T, R>) -> BoxedGroundQuery
{
BoxedGroundQuery {
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))
})
}
impl QueryRegistry {
fn new() -> QueryRegistry {
let mut reg = QueryRegistry { imp: imp::QueryRegistry::new() };
queries::register_queries(&mut reg);
::module_map_db::register_queries(&mut reg);
reg
}
pub(crate) fn add<Q: imp::EvalQuery>(&mut self, q: Q, name: &'static str) {
self.imp.add(q, name)
}
}
pub(crate) struct BoxedQuery {
query_type: salsa::QueryTypeId,
f: Box<Fn(&salsa::QueryCtx<State, Data>, &Data) -> (Data, salsa::OutputFingerprint) + Send + Sync + 'static>,
}
impl<T, R> From<Query<T, R>> for BoxedQuery
where
T: Hash + Send + Sync + 'static,
R: Hash + Send + Sync + 'static,
{
fn from(q: Query<T, R>) -> BoxedQuery
{
BoxedQuery {
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<T: ::std::hash::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()
}