yet another db api
This commit is contained in:
@@ -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(¶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)
|
||||
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(¶ms)),
|
||||
);
|
||||
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(¶ms)),
|
||||
);
|
||||
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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user