mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 21:28:51 +00:00
be generic over data
This commit is contained in:
parent
8cf9c27196
commit
cecc7ad5b2
2 changed files with 61 additions and 55 deletions
|
@ -3,53 +3,52 @@ extern crate parking_lot;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
any::Any,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
type GroundQueryFn<T> = fn(&T, &(Any + Send + Sync + 'static)) -> (Box<Any + Send + Sync + 'static>, OutputFingerprint);
|
type GroundQueryFn<T, D> = fn(&T, &D) -> (D, OutputFingerprint);
|
||||||
type QueryFn<T> = fn(&QueryCtx<T>, &(Any + Send + Sync + 'static)) -> (Box<Any + Send + Sync + 'static>, OutputFingerprint);
|
type QueryFn<T, D> = fn(&QueryCtx<T, D>, &D) -> (D, OutputFingerprint);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Db<T> {
|
pub struct Db<T, D> {
|
||||||
db: Arc<DbState<T>>,
|
db: Arc<DbState<T, D>>,
|
||||||
query_config: Arc<QueryConfig<T>>,
|
query_config: Arc<QueryConfig<T, D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QueryConfig<T> {
|
pub struct QueryConfig<T, D> {
|
||||||
ground_fn: HashMap<QueryTypeId, GroundQueryFn<T>>,
|
ground_fn: HashMap<QueryTypeId, GroundQueryFn<T, D>>,
|
||||||
query_fn: HashMap<QueryTypeId, QueryFn<T>>,
|
query_fn: HashMap<QueryTypeId, QueryFn<T, D>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ::std::fmt::Debug for QueryConfig<T> {
|
impl<T, D> ::std::fmt::Debug for QueryConfig<T, D> {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
::std::fmt::Display::fmt("QueryConfig { ... }", f)
|
::std::fmt::Display::fmt("QueryConfig { ... }", f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct DbState<T> {
|
struct DbState<T, D> {
|
||||||
ground_data: T,
|
ground_data: T,
|
||||||
gen: Gen,
|
gen: Gen,
|
||||||
graph: Mutex<im::HashMap<QueryId, (Gen, Arc<QueryRecord>)>>,
|
graph: Mutex<im::HashMap<QueryId, (Gen, Arc<QueryRecord<D>>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct QueryRecord {
|
struct QueryRecord<D> {
|
||||||
params: Arc<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
output: Arc<Any + Send + Sync + 'static>,
|
output: D,
|
||||||
output_fingerprint: OutputFingerprint,
|
output_fingerprint: OutputFingerprint,
|
||||||
deps: Vec<(QueryId, OutputFingerprint)>,
|
deps: Vec<(QueryId, OutputFingerprint)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DbState<T> {
|
impl<T, D> DbState<T, D> {
|
||||||
fn record(
|
fn record(
|
||||||
&self,
|
&self,
|
||||||
query_id: QueryId,
|
query_id: QueryId,
|
||||||
params: Arc<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
output: Arc<Any + Send + Sync + 'static>,
|
output: D,
|
||||||
output_fingerprint: OutputFingerprint,
|
output_fingerprint: OutputFingerprint,
|
||||||
deps: Vec<(QueryId, OutputFingerprint)>,
|
deps: Vec<(QueryId, OutputFingerprint)>,
|
||||||
) {
|
) {
|
||||||
|
@ -64,7 +63,7 @@ impl<T> DbState<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> QueryConfig<T> {
|
impl<T, D> QueryConfig<T, D> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
QueryConfig {
|
QueryConfig {
|
||||||
ground_fn: HashMap::new(),
|
ground_fn: HashMap::new(),
|
||||||
|
@ -74,7 +73,7 @@ impl<T> QueryConfig<T> {
|
||||||
pub fn with_ground_query(
|
pub fn with_ground_query(
|
||||||
mut self,
|
mut self,
|
||||||
query_type: QueryTypeId,
|
query_type: QueryTypeId,
|
||||||
query_fn: GroundQueryFn<T>
|
query_fn: GroundQueryFn<T, D>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let prev = self.ground_fn.insert(query_type, query_fn);
|
let prev = self.ground_fn.insert(query_type, query_fn);
|
||||||
assert!(prev.is_none());
|
assert!(prev.is_none());
|
||||||
|
@ -83,7 +82,7 @@ impl<T> QueryConfig<T> {
|
||||||
pub fn with_query(
|
pub fn with_query(
|
||||||
mut self,
|
mut self,
|
||||||
query_type: QueryTypeId,
|
query_type: QueryTypeId,
|
||||||
query_fn: QueryFn<T>,
|
query_fn: QueryFn<T, D>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let prev = self.query_fn.insert(query_type, query_fn);
|
let prev = self.query_fn.insert(query_type, query_fn);
|
||||||
assert!(prev.is_none());
|
assert!(prev.is_none());
|
||||||
|
@ -91,15 +90,18 @@ impl<T> QueryConfig<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QueryCtx<T> {
|
pub struct QueryCtx<T, D> {
|
||||||
db: Arc<DbState<T>>,
|
db: Arc<DbState<T, D>>,
|
||||||
query_config: Arc<QueryConfig<T>>,
|
query_config: Arc<QueryConfig<T, D>>,
|
||||||
stack: RefCell<Vec<Vec<(QueryId, OutputFingerprint)>>>,
|
stack: RefCell<Vec<Vec<(QueryId, OutputFingerprint)>>>,
|
||||||
executed: RefCell<Vec<QueryTypeId>>,
|
executed: RefCell<Vec<QueryTypeId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> QueryCtx<T> {
|
impl<T, D> QueryCtx<T, D>
|
||||||
fn new(db: &Db<T>) -> QueryCtx<T> {
|
where
|
||||||
|
D: Clone
|
||||||
|
{
|
||||||
|
fn new(db: &Db<T, D>) -> QueryCtx<T, D> {
|
||||||
QueryCtx {
|
QueryCtx {
|
||||||
db: Arc::clone(&db.db),
|
db: Arc::clone(&db.db),
|
||||||
query_config: Arc::clone(&db.query_config),
|
query_config: Arc::clone(&db.query_config),
|
||||||
|
@ -110,8 +112,8 @@ impl<T> QueryCtx<T> {
|
||||||
pub fn get(
|
pub fn get(
|
||||||
&self,
|
&self,
|
||||||
query_id: QueryId,
|
query_id: QueryId,
|
||||||
params: Arc<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
) -> Arc<Any + Send + Sync + 'static> {
|
) -> D {
|
||||||
let (res, output_fingerprint) = self.get_inner(query_id, params);
|
let (res, output_fingerprint) = self.get_inner(query_id, params);
|
||||||
self.record_dep(query_id, output_fingerprint);
|
self.record_dep(query_id, output_fingerprint);
|
||||||
res
|
res
|
||||||
|
@ -120,8 +122,8 @@ impl<T> QueryCtx<T> {
|
||||||
pub fn get_inner(
|
pub fn get_inner(
|
||||||
&self,
|
&self,
|
||||||
query_id: QueryId,
|
query_id: QueryId,
|
||||||
params: Arc<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
) -> (Arc<Any + Send + Sync + 'static>, OutputFingerprint) {
|
) -> (D, OutputFingerprint) {
|
||||||
let (gen, record) = {
|
let (gen, record) = {
|
||||||
let guard = self.db.graph.lock();
|
let guard = self.db.graph.lock();
|
||||||
match guard.get(&query_id).map(|it| it.clone()){
|
match guard.get(&query_id).map(|it| it.clone()){
|
||||||
|
@ -139,7 +141,7 @@ impl<T> QueryCtx<T> {
|
||||||
return self.force(query_id, params);
|
return self.force(query_id, params);
|
||||||
}
|
}
|
||||||
for (dep_query_id, prev_fingerprint) in record.deps.iter().cloned() {
|
for (dep_query_id, prev_fingerprint) in record.deps.iter().cloned() {
|
||||||
let dep_params: Arc<Any + Send + Sync + 'static> = {
|
let dep_params: D = {
|
||||||
let guard = self.db.graph.lock();
|
let guard = self.db.graph.lock();
|
||||||
guard[&dep_query_id]
|
guard[&dep_query_id]
|
||||||
.1
|
.1
|
||||||
|
@ -160,29 +162,29 @@ impl<T> QueryCtx<T> {
|
||||||
fn force(
|
fn force(
|
||||||
&self,
|
&self,
|
||||||
query_id: QueryId,
|
query_id: QueryId,
|
||||||
params: Arc<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
) -> (Arc<Any + Send + Sync + 'static>, OutputFingerprint) {
|
) -> (D, OutputFingerprint) {
|
||||||
self.executed.borrow_mut().push(query_id.0);
|
self.executed.borrow_mut().push(query_id.0);
|
||||||
self.stack.borrow_mut().push(Vec::new());
|
self.stack.borrow_mut().push(Vec::new());
|
||||||
|
|
||||||
let (res, output_fingerprint) = if let Some(f) = self.ground_query_fn_by_type(query_id.0) {
|
let (res, output_fingerprint) = if let Some(f) = self.ground_query_fn_by_type(query_id.0) {
|
||||||
f(&self.db.ground_data, &*params)
|
f(&self.db.ground_data, ¶ms)
|
||||||
} else if let Some(f) = self.query_fn_by_type(query_id.0) {
|
} else if let Some(f) = self.query_fn_by_type(query_id.0) {
|
||||||
f(self, &*params)
|
f(self, ¶ms)
|
||||||
} else {
|
} else {
|
||||||
panic!("unknown query type: {:?}", query_id.0);
|
panic!("unknown query type: {:?}", query_id.0);
|
||||||
};
|
};
|
||||||
|
|
||||||
let res: Arc<Any + Send + Sync + 'static> = res.into();
|
let res: D = res.into();
|
||||||
|
|
||||||
let deps = self.stack.borrow_mut().pop().unwrap();
|
let deps = self.stack.borrow_mut().pop().unwrap();
|
||||||
self.db.record(query_id, params, res.clone(), output_fingerprint, deps);
|
self.db.record(query_id, params, res.clone(), output_fingerprint, deps);
|
||||||
(res, output_fingerprint)
|
(res, output_fingerprint)
|
||||||
}
|
}
|
||||||
fn ground_query_fn_by_type(&self, query_type: QueryTypeId) -> Option<GroundQueryFn<T>> {
|
fn ground_query_fn_by_type(&self, query_type: QueryTypeId) -> Option<GroundQueryFn<T, D>> {
|
||||||
self.query_config.ground_fn.get(&query_type).map(|&it| it)
|
self.query_config.ground_fn.get(&query_type).map(|&it| it)
|
||||||
}
|
}
|
||||||
fn query_fn_by_type(&self, query_type: QueryTypeId) -> Option<QueryFn<T>> {
|
fn query_fn_by_type(&self, query_type: QueryTypeId) -> Option<QueryFn<T, D>> {
|
||||||
self.query_config.query_fn.get(&query_type).map(|&it| it)
|
self.query_config.query_fn.get(&query_type).map(|&it| it)
|
||||||
}
|
}
|
||||||
fn record_dep(
|
fn record_dep(
|
||||||
|
@ -196,15 +198,18 @@ impl<T> QueryCtx<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Db<T> {
|
impl<T, D> Db<T, D>
|
||||||
pub fn new(query_config: QueryConfig<T>, ground_data: T) -> Db<T> {
|
where
|
||||||
|
D: Clone
|
||||||
|
{
|
||||||
|
pub fn new(query_config: QueryConfig<T, D>, ground_data: T) -> Db<T, D> {
|
||||||
Db {
|
Db {
|
||||||
db: Arc::new(DbState { ground_data, gen: Gen(0), graph: Default::default() }),
|
db: Arc::new(DbState { ground_data, gen: Gen(0), graph: Default::default() }),
|
||||||
query_config: Arc::new(query_config),
|
query_config: Arc::new(query_config),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_ground_data(&self, ground_data: T) -> Db<T> {
|
pub fn with_ground_data(&self, ground_data: T) -> Db<T, D> {
|
||||||
let gen = Gen(self.db.gen.0 + 1);
|
let gen = Gen(self.db.gen.0 + 1);
|
||||||
let graph = self.db.graph.lock().clone();
|
let graph = self.db.graph.lock().clone();
|
||||||
let graph = Mutex::new(graph);
|
let graph = Mutex::new(graph);
|
||||||
|
@ -216,8 +221,8 @@ impl<T> Db<T> {
|
||||||
pub fn get(
|
pub fn get(
|
||||||
&self,
|
&self,
|
||||||
query_id: QueryId,
|
query_id: QueryId,
|
||||||
params: Box<Any + Send + Sync + 'static>,
|
params: D,
|
||||||
) -> (Arc<Any + Send + Sync + 'static>, Vec<QueryTypeId>) {
|
) -> (D, Vec<QueryTypeId>) {
|
||||||
let ctx = QueryCtx::new(self);
|
let ctx = QueryCtx::new(self);
|
||||||
let res = ctx.get(query_id, params.into());
|
let res = ctx.get(query_id, params.into());
|
||||||
let executed = ::std::mem::replace(&mut *ctx.executed.borrow_mut(), Vec::new());
|
let executed = ::std::mem::replace(&mut *ctx.executed.borrow_mut(), Vec::new());
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = HashMap<u32, String>;
|
type State = HashMap<u32, String>;
|
||||||
|
type Data = Arc<Any + Send + Sync + 'static>;
|
||||||
const GET_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(1);
|
const GET_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(1);
|
||||||
const GET_FILES: salsa::QueryTypeId = salsa::QueryTypeId(2);
|
const GET_FILES: salsa::QueryTypeId = salsa::QueryTypeId(2);
|
||||||
const FILE_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(3);
|
const FILE_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(3);
|
||||||
|
@ -14,9 +15,9 @@ const TOTAL_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(4);
|
||||||
|
|
||||||
fn mk_ground_query<T, R>(
|
fn mk_ground_query<T, R>(
|
||||||
state: &State,
|
state: &State,
|
||||||
params: &(Any + Send + Sync + 'static),
|
params: &Data,
|
||||||
f: fn(&State, &T) -> R,
|
f: fn(&State, &T) -> R,
|
||||||
) -> (Box<Any + Send + Sync + 'static>, salsa::OutputFingerprint)
|
) -> (Data, salsa::OutputFingerprint)
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
R: Hash + Send + Sync + 'static,
|
R: Hash + Send + Sync + 'static,
|
||||||
|
@ -24,21 +25,21 @@ where
|
||||||
let params = params.downcast_ref().unwrap();
|
let params = params.downcast_ref().unwrap();
|
||||||
let result = f(state, params);
|
let result = f(state, params);
|
||||||
let fingerprint = o_print(&result);
|
let fingerprint = o_print(&result);
|
||||||
(Box::new(result), fingerprint)
|
(Arc::new(result), fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get<T, R>(db: &salsa::Db<State>, query_type: salsa::QueryTypeId, param: T) -> (Arc<R>, Vec<salsa::QueryTypeId>)
|
fn get<T, R>(db: &salsa::Db<State, Data>, query_type: salsa::QueryTypeId, param: T) -> (Arc<R>, Vec<salsa::QueryTypeId>)
|
||||||
where
|
where
|
||||||
T: Hash + Send + Sync + 'static,
|
T: Hash + Send + Sync + 'static,
|
||||||
R: Send + Sync + 'static,
|
R: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let i_print = i_print(¶m);
|
let i_print = i_print(¶m);
|
||||||
let param = Box::new(param);
|
let param = Arc::new(param);
|
||||||
let (res, trace) = db.get(salsa::QueryId(query_type, i_print), param);
|
let (res, trace) = db.get(salsa::QueryId(query_type, i_print), param);
|
||||||
(res.downcast().unwrap(), trace)
|
(res.downcast().unwrap(), trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueryCtx<'a>(&'a salsa::QueryCtx<State>);
|
struct QueryCtx<'a>(&'a salsa::QueryCtx<State, Data>);
|
||||||
|
|
||||||
impl<'a> QueryCtx<'a> {
|
impl<'a> QueryCtx<'a> {
|
||||||
fn get_text(&self, id: u32) -> Arc<String> {
|
fn get_text(&self, id: u32) -> Arc<String> {
|
||||||
|
@ -60,10 +61,10 @@ impl<'a> QueryCtx<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_query<T, R>(
|
fn mk_query<T, R>(
|
||||||
query_ctx: &salsa::QueryCtx<State>,
|
query_ctx: &salsa::QueryCtx<State, Data>,
|
||||||
params: &(Any + Send + Sync + 'static),
|
params: &Data,
|
||||||
f: fn(QueryCtx, &T) -> R,
|
f: fn(QueryCtx, &T) -> R,
|
||||||
) -> (Box<Any + Send + Sync + 'static>, salsa::OutputFingerprint)
|
) -> (Data, salsa::OutputFingerprint)
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
R: Hash + Send + Sync + 'static,
|
R: Hash + Send + Sync + 'static,
|
||||||
|
@ -72,11 +73,11 @@ where
|
||||||
let query_ctx = QueryCtx(query_ctx);
|
let query_ctx = QueryCtx(query_ctx);
|
||||||
let result = f(query_ctx, params);
|
let result = f(query_ctx, params);
|
||||||
let fingerprint = o_print(&result);
|
let fingerprint = o_print(&result);
|
||||||
(Box::new(result), fingerprint)
|
(Arc::new(result), fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_queries() -> salsa::QueryConfig<State> {
|
fn mk_queries() -> salsa::QueryConfig<State, Data> {
|
||||||
salsa::QueryConfig::<State>::new()
|
salsa::QueryConfig::<State, Data>::new()
|
||||||
.with_ground_query(GET_TEXT, |state, id| {
|
.with_ground_query(GET_TEXT, |state, id| {
|
||||||
mk_ground_query::<u32, String>(state, id, |state, id| state[id].clone())
|
mk_ground_query::<u32, String>(state, id, |state, id| state[id].clone())
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue