diff --git a/examples/hello_world/implementation.rs b/examples/hello_world/implementation.rs index a1288332..9f88c156 100644 --- a/examples/hello_world/implementation.rs +++ b/examples/hello_world/implementation.rs @@ -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, storage: QueryContextImplStorage, interner: Interner, - execution_stack: RefCell>, } // 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( - &self, - descriptor: Self::QueryDescriptor, - key: &Q::Key, - ) -> Q::Value - where - Q: Query, - { - 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 { + &self.runtime } } diff --git a/examples/storage_varieties/implementation.rs b/examples/storage_varieties/implementation.rs index 0a4469a4..79725edd 100644 --- a/examples/storage_varieties/implementation.rs +++ b/examples/storage_varieties/implementation.rs @@ -3,6 +3,7 @@ use std::cell::Cell; #[derive(Default)] pub struct QueryContextImpl { + runtime: salsa::Runtime, storage: QueryContextImplStorage, counter: Cell, } @@ -27,19 +28,7 @@ impl queries::CounterContext for QueryContextImpl { impl salsa::BaseQueryContext for QueryContextImpl { type QueryDescriptor = salsa::dyn_descriptor::DynDescriptor; - fn execute_query_implementation( - &self, - _descriptor: Self::QueryDescriptor, - key: &Q::Key, - ) -> Q::Value - where - Q: salsa::Query, - { - 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 { + &self.runtime } } diff --git a/src/lib.rs b/src/lib.rs index 5f006259..97f14831 100644 --- a/src/lib.rs +++ b/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( - &self, - descriptor: Self::QueryDescriptor, - key: &Q::Key, - ) -> Q::Value - where - Q: Query; - - /// 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; } pub trait Query: 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, diff --git a/src/memoized.rs b/src/memoized.rs index a4cf9495..3107c2ec 100644 --- a/src/memoized.rs +++ b/src/memoized.rs @@ -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::(descriptor, key); + let value = query + .salsa_runtime() + .execute_query_implementation::(query, descriptor, key); { let mut map_write = self.map.write(); diff --git a/src/runtime.rs b/src/runtime.rs new file mode 100644 index 00000000..4bef72ca --- /dev/null +++ b/src/runtime.rs @@ -0,0 +1,58 @@ +use crate::BaseQueryContext; +use crate::Query; +use std::cell::RefCell; +use std::fmt::Write; + +pub struct Runtime +where + QC: BaseQueryContext, +{ + execution_stack: RefCell>, +} + +impl Default for Runtime +where + QC: BaseQueryContext, +{ + fn default() -> Self { + Runtime { + execution_stack: RefCell::default(), + } + } +} + +impl Runtime +where + QC: BaseQueryContext, +{ + crate fn execute_query_implementation( + &self, + query: &QC, + descriptor: QC::QueryDescriptor, + key: &Q::Key, + ) -> Q::Value + where + Q: Query, + { + 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) + } +} diff --git a/src/transparent.rs b/src/transparent.rs index c0132602..c0b4fb3c 100644 --- a/src/transparent.rs +++ b/src/transparent.rs @@ -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::(descriptor, key)) + Ok(query + .salsa_runtime() + .execute_query_implementation::(query, descriptor, key)) } }