mirror of
https://github.com/salsa-rs/salsa.git
synced 2024-12-27 06:27:45 +00:00
add a "runtime" and use that from query context impls
This commit is contained in:
parent
ac7b02b7ef
commit
288fe5b25f
6 changed files with 82 additions and 62 deletions
|
@ -1,17 +1,13 @@
|
|||
use crate::class_table;
|
||||
use crate::compiler::{CompilerQueryContext, Interner};
|
||||
use salsa::dyn_descriptor::DynDescriptor;
|
||||
use salsa::query_context_storage;
|
||||
use salsa::BaseQueryContext;
|
||||
use salsa::Query;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct QueryContextImpl {
|
||||
runtime: salsa::Runtime<QueryContextImpl>,
|
||||
storage: QueryContextImplStorage,
|
||||
interner: Interner,
|
||||
execution_stack: RefCell<Vec<DynDescriptor>>,
|
||||
}
|
||||
|
||||
// This is an example of how you "link up" all the queries in your
|
||||
|
@ -42,34 +38,9 @@ impl CompilerQueryContext for QueryContextImpl {
|
|||
// permit behavior refinement.
|
||||
|
||||
impl BaseQueryContext for QueryContextImpl {
|
||||
type QueryDescriptor = DynDescriptor;
|
||||
type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor;
|
||||
|
||||
fn execute_query_implementation<Q>(
|
||||
&self,
|
||||
descriptor: Self::QueryDescriptor,
|
||||
key: &Q::Key,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: Query<Self>,
|
||||
{
|
||||
self.execution_stack.borrow_mut().push(descriptor);
|
||||
let value = Q::execute(self, key.clone());
|
||||
self.execution_stack.borrow_mut().pop();
|
||||
value
|
||||
}
|
||||
|
||||
fn report_unexpected_cycle(&self, descriptor: Self::QueryDescriptor) -> ! {
|
||||
let execution_stack = self.execution_stack.borrow();
|
||||
let start_index = (0..execution_stack.len())
|
||||
.rev()
|
||||
.filter(|&i| execution_stack[i] == descriptor)
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let mut message = format!("Internal error, cycle detected:\n");
|
||||
for descriptor in &execution_stack[start_index..] {
|
||||
writeln!(message, "- {:?}\n", descriptor).unwrap();
|
||||
}
|
||||
panic!(message)
|
||||
fn salsa_runtime(&self) -> &salsa::runtime::Runtime<QueryContextImpl> {
|
||||
&self.runtime
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::cell::Cell;
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct QueryContextImpl {
|
||||
runtime: salsa::Runtime<QueryContextImpl>,
|
||||
storage: QueryContextImplStorage,
|
||||
counter: Cell<usize>,
|
||||
}
|
||||
|
@ -27,19 +28,7 @@ impl queries::CounterContext for QueryContextImpl {
|
|||
impl salsa::BaseQueryContext for QueryContextImpl {
|
||||
type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor;
|
||||
|
||||
fn execute_query_implementation<Q>(
|
||||
&self,
|
||||
_descriptor: Self::QueryDescriptor,
|
||||
key: &Q::Key,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: salsa::Query<Self>,
|
||||
{
|
||||
let value = Q::execute(self, key.clone());
|
||||
value
|
||||
}
|
||||
|
||||
fn report_unexpected_cycle(&self, _descriptor: Self::QueryDescriptor) -> ! {
|
||||
panic!("cycle")
|
||||
fn salsa_runtime(&self) -> &salsa::runtime::Runtime<QueryContextImpl> {
|
||||
&self.runtime
|
||||
}
|
||||
}
|
||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -1,5 +1,6 @@
|
|||
#![deny(rust_2018_idioms)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(nll)]
|
||||
#![feature(min_const_fn)]
|
||||
#![feature(const_fn)]
|
||||
|
@ -20,8 +21,11 @@ use std::hash::Hash;
|
|||
|
||||
pub mod dyn_descriptor;
|
||||
pub mod memoized;
|
||||
pub mod runtime;
|
||||
pub mod transparent;
|
||||
|
||||
pub use self::runtime::Runtime;
|
||||
|
||||
pub trait BaseQueryContext: Sized {
|
||||
/// A "query descriptor" packages up all the possible queries and a key.
|
||||
/// It is used to store information about (e.g.) the stack.
|
||||
|
@ -31,16 +35,8 @@ pub trait BaseQueryContext: Sized {
|
|||
/// for a more open-ended option.
|
||||
type QueryDescriptor: Debug + Eq;
|
||||
|
||||
fn execute_query_implementation<Q>(
|
||||
&self,
|
||||
descriptor: Self::QueryDescriptor,
|
||||
key: &Q::Key,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: Query<Self>;
|
||||
|
||||
/// Reports an unexpected cycle attempting to access the query Q with the given key.
|
||||
fn report_unexpected_cycle(&self, descriptor: Self::QueryDescriptor) -> !;
|
||||
/// Gives access to the underlying salsa runtime.
|
||||
fn salsa_runtime(&self) -> &runtime::Runtime<Self>;
|
||||
}
|
||||
|
||||
pub trait Query<QC: BaseQueryContext>: Debug + Default + Sized + 'static {
|
||||
|
@ -86,7 +82,9 @@ where
|
|||
self.storage
|
||||
.try_fetch(self.query, &key, || self.descriptor(&key))
|
||||
.unwrap_or_else(|CycleDetected| {
|
||||
self.query.report_unexpected_cycle(self.descriptor(&key))
|
||||
self.query
|
||||
.salsa_runtime()
|
||||
.report_unexpected_cycle(self.descriptor(&key))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -301,6 +299,8 @@ macro_rules! query_definition {
|
|||
};
|
||||
}
|
||||
|
||||
/// This macro generates the "query storage" that goes into your query
|
||||
/// context.
|
||||
#[macro_export]
|
||||
macro_rules! query_context_storage {
|
||||
(
|
||||
|
@ -336,8 +336,6 @@ macro_rules! query_context_storage {
|
|||
self,
|
||||
&self.$storage_field.$query_method,
|
||||
|
||||
// FIXME: we should not hardcode the descriptor like this.
|
||||
// Have to think of the best fix.
|
||||
$crate::dyn_descriptor::DynDescriptor::from_key::<
|
||||
Self,
|
||||
$QueryType,
|
||||
|
|
|
@ -75,7 +75,9 @@ where
|
|||
// If we get here, the query is in progress, and we are the
|
||||
// ones tasked with finding its final value.
|
||||
let descriptor = descriptor();
|
||||
let value = query.execute_query_implementation::<Q>(descriptor, key);
|
||||
let value = query
|
||||
.salsa_runtime()
|
||||
.execute_query_implementation::<Q>(query, descriptor, key);
|
||||
|
||||
{
|
||||
let mut map_write = self.map.write();
|
||||
|
|
58
src/runtime.rs
Normal file
58
src/runtime.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use crate::BaseQueryContext;
|
||||
use crate::Query;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Write;
|
||||
|
||||
pub struct Runtime<QC>
|
||||
where
|
||||
QC: BaseQueryContext,
|
||||
{
|
||||
execution_stack: RefCell<Vec<QC::QueryDescriptor>>,
|
||||
}
|
||||
|
||||
impl<QC> Default for Runtime<QC>
|
||||
where
|
||||
QC: BaseQueryContext,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Runtime {
|
||||
execution_stack: RefCell::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<QC> Runtime<QC>
|
||||
where
|
||||
QC: BaseQueryContext,
|
||||
{
|
||||
crate fn execute_query_implementation<Q>(
|
||||
&self,
|
||||
query: &QC,
|
||||
descriptor: QC::QueryDescriptor,
|
||||
key: &Q::Key,
|
||||
) -> Q::Value
|
||||
where
|
||||
Q: Query<QC>,
|
||||
{
|
||||
self.execution_stack.borrow_mut().push(descriptor);
|
||||
let value = Q::execute(query, key.clone());
|
||||
self.execution_stack.borrow_mut().pop();
|
||||
value
|
||||
}
|
||||
|
||||
/// Obviously, this should be user configurable at some point.
|
||||
crate fn report_unexpected_cycle(&self, descriptor: QC::QueryDescriptor) -> ! {
|
||||
let execution_stack = self.execution_stack.borrow();
|
||||
let start_index = (0..execution_stack.len())
|
||||
.rev()
|
||||
.filter(|&i| execution_stack[i] == descriptor)
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let mut message = format!("Internal error, cycle detected:\n");
|
||||
for descriptor in &execution_stack[start_index..] {
|
||||
writeln!(message, "- {:?}\n", descriptor).unwrap();
|
||||
}
|
||||
panic!(message)
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ where
|
|||
// here? Or should we just call `Q::execute`, and maybe
|
||||
// separate out the `push`/`pop` operations.
|
||||
let descriptor = descriptor();
|
||||
Ok(query.execute_query_implementation::<Q>(descriptor, key))
|
||||
Ok(query
|
||||
.salsa_runtime()
|
||||
.execute_query_implementation::<Q>(query, descriptor, key))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue