diff --git a/examples/hello_world/class_table.rs b/examples/hello_world/class_table.rs index 157239bf..bde87b30 100644 --- a/examples/hello_world/class_table.rs +++ b/examples/hello_world/class_table.rs @@ -19,23 +19,23 @@ pub trait ClassTableQueryContext: compiler::CompilerQueryContext { ); } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct DefId; +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct DefId(usize); query_definition! { pub AllClasses(_: &impl ClassTableQueryContext, (): ()) -> Arc> { - Arc::new(vec![]) // dummy impl + Arc::new(vec![DefId(0), DefId(10)]) // dummy impl } } query_definition! { - pub Fields(_: &impl ClassTableQueryContext, _class: DefId) -> Arc> { - Arc::new(vec![]) // dummy impl + pub Fields(_: &impl ClassTableQueryContext, class: DefId) -> Arc> { + Arc::new(vec![DefId(class.0 + 1), DefId(class.0 + 2)]) // dummy impl } } query_definition! { - pub AllFields(query: &impl ClassTableQueryContext, _class: DefId) -> Arc> { + pub AllFields(query: &impl ClassTableQueryContext, (): ()) -> Arc> { Arc::new( query.all_classes() .of(()) @@ -43,7 +43,7 @@ query_definition! { .cloned() .flat_map(|def_id| { let fields = query.fields().of(def_id); - (0..fields.len()).map(move |i| fields[i].clone()) + (0..fields.len()).map(move |i| fields[i]) }) .collect() ) diff --git a/examples/hello_world/compiler.rs b/examples/hello_world/compiler.rs index 4477c8a1..5cedd221 100644 --- a/examples/hello_world/compiler.rs +++ b/examples/hello_world/compiler.rs @@ -2,5 +2,5 @@ pub trait CompilerQueryContext: salsa::BaseQueryContext { fn interner(&self) -> &Interner; } -#[derive(Clone)] +#[derive(Clone, Default)] pub struct Interner; diff --git a/examples/hello_world/implementation.rs b/examples/hello_world/implementation.rs new file mode 100644 index 00000000..a6790419 --- /dev/null +++ b/examples/hello_world/implementation.rs @@ -0,0 +1,92 @@ +use crate::class_table::{self, ClassTableQueryContext}; +use crate::compiler::{CompilerQueryContext, Interner}; +use salsa::dyn_descriptor::DynDescriptor; +use salsa::BaseQueryContext; +use salsa::Query; +use salsa::QueryTable; +use std::cell::RefCell; +use std::fmt::Write; + +#[derive(Default)] +pub struct QueryContextImpl { + storage: QueryContextImplStorage, + interner: Interner, + execution_stack: RefCell>, +} + +// The intention is that plus the impl of `ClassTableQueryContext` +// below will eventually be generated by a macro, so that you just +// have to name the queries. + +#[allow(non_snake_case)] +#[derive(Default)] +struct QueryContextImplStorage { + AllClasses: >::Storage, + AllFields: >::Storage, + Fields: >::Storage, +} + +impl ClassTableQueryContext for QueryContextImpl { + fn all_classes(&self) -> QueryTable<'_, Self, class_table::AllClasses> { + QueryTable::new( + self, + &self.storage.AllClasses, + DynDescriptor::from_key::, + ) + } + + fn all_fields(&self) -> QueryTable<'_, Self, class_table::AllFields> { + QueryTable::new( + self, + &self.storage.AllFields, + DynDescriptor::from_key::, + ) + } + + fn fields(&self) -> QueryTable<'_, Self, class_table::Fields> { + QueryTable::new( + self, + &self.storage.Fields, + DynDescriptor::from_key::, + ) + } +} + +impl CompilerQueryContext for QueryContextImpl { + fn interner(&self) -> &Interner { + &self.interner + } +} + +impl BaseQueryContext for QueryContextImpl { + type QueryDescriptor = 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) + } +} diff --git a/examples/hello_world/main.rs b/examples/hello_world/main.rs index 4f700d9b..3e74c0e2 100644 --- a/examples/hello_world/main.rs +++ b/examples/hello_world/main.rs @@ -1,6 +1,13 @@ mod class_table; mod compiler; +mod implementation; + +use self::class_table::ClassTableQueryContext; +use self::implementation::QueryContextImpl; fn main() { - println!("It builds."); + let query = QueryContextImpl::default(); + for f in query.all_fields().of(()).iter() { + println!("{:?}", f); + } } diff --git a/src/lib.rs b/src/lib.rs index d40c6867..ae016481 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ pub trait Query: Debug + Default + Sized + 'static { fn execute(query: &QC, key: Self::Key) -> Self::Value; } -pub trait QueryStorageOps +pub trait QueryStorageOps: Default where QC: BaseQueryContext, Q: Query, diff --git a/src/storage.rs b/src/storage.rs index 0d41db68..8aa15054 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -25,6 +25,18 @@ where map: RefCell>>, } +impl Default for MemoizedStorage +where + Q: Query, + QC: BaseQueryContext, +{ + fn default() -> Self { + MemoizedStorage { + map: RefCell::new(FxHashMap::default()), + } + } +} + impl QueryStorageOps for MemoizedStorage where Q: Query,