From e134ffcdf43b0295d4218f6f3bb3e324de24a40e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 30 Sep 2018 06:59:28 -0400 Subject: [PATCH] add a public `next_revision` method and start on incremental test --- Cargo.toml | 3 ++ examples/incremental/counter.rs | 14 ++++++++++ examples/incremental/implementation.rs | 36 ++++++++++++++++++++++++ examples/incremental/log.rs | 16 +++++++++++ examples/incremental/main.rs | 10 +++++++ examples/incremental/queries.rs | 38 ++++++++++++++++++++++++++ examples/incremental/tests.rs | 23 ++++++++++++++++ src/runtime.rs | 18 ++++++++++++ 8 files changed, 158 insertions(+) create mode 100644 examples/incremental/counter.rs create mode 100644 examples/incremental/implementation.rs create mode 100644 examples/incremental/log.rs create mode 100644 examples/incremental/main.rs create mode 100644 examples/incremental/queries.rs create mode 100644 examples/incremental/tests.rs diff --git a/Cargo.toml b/Cargo.toml index ca875f91..a1d116a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,6 @@ derive-new = "0.5.5" rustc-hash = "1.0" parking_lot = "0.6.4" indexmap = "1.0.1" + +[dev-dependencies] +text-diff = "0.4.0" \ No newline at end of file diff --git a/examples/incremental/counter.rs b/examples/incremental/counter.rs new file mode 100644 index 00000000..f0d5fbb6 --- /dev/null +++ b/examples/incremental/counter.rs @@ -0,0 +1,14 @@ +use std::cell::Cell; + +#[derive(Default)] +crate struct Counter { + value: Cell, +} + +impl Counter { + crate fn increment(&self) -> usize { + let v = self.value.get(); + self.value.set(v + 1); + v + } +} diff --git a/examples/incremental/implementation.rs b/examples/incremental/implementation.rs new file mode 100644 index 00000000..c89d060b --- /dev/null +++ b/examples/incremental/implementation.rs @@ -0,0 +1,36 @@ +use crate::counter::Counter; +use crate::log::Log; +use crate::queries; + +#[derive(Default)] +pub struct QueryContextImpl { + runtime: salsa::runtime::Runtime, + clock: Counter, + log: Log, +} + +salsa::query_context_storage! { + pub struct QueryContextImplStorage for QueryContextImpl { + impl queries::QueryContext { + fn memoized2() for queries::Memoized2; + fn memoized1() for queries::Memoized1; + fn volatile() for queries::Volatile; + } + } +} + +impl queries::CounterContext for QueryContextImpl { + fn clock(&self) -> &Counter { + &self.clock + } + + fn log(&self) -> &Log { + &self.log + } +} + +impl salsa::QueryContext for QueryContextImpl { + fn salsa_runtime(&self) -> &salsa::runtime::Runtime { + &self.runtime + } +} diff --git a/examples/incremental/log.rs b/examples/incremental/log.rs new file mode 100644 index 00000000..55eceb97 --- /dev/null +++ b/examples/incremental/log.rs @@ -0,0 +1,16 @@ +use std::cell::RefCell; + +#[derive(Default)] +crate struct Log { + data: RefCell>, +} + +impl Log { + crate fn add(&self, text: impl Into) { + self.data.borrow_mut().push(text.into()); + } + + crate fn read(&self) -> Vec { + self.data.borrow().clone() + } +} diff --git a/examples/incremental/main.rs b/examples/incremental/main.rs new file mode 100644 index 00000000..38095b91 --- /dev/null +++ b/examples/incremental/main.rs @@ -0,0 +1,10 @@ +#![feature(crate_visibility_modifier)] +#![feature(underscore_imports)] + +mod counter; +mod implementation; +mod log; +mod queries; +mod tests; + +fn main() {} diff --git a/examples/incremental/queries.rs b/examples/incremental/queries.rs new file mode 100644 index 00000000..65ac9d69 --- /dev/null +++ b/examples/incremental/queries.rs @@ -0,0 +1,38 @@ +use crate::counter::Counter; +use crate::log::Log; + +crate trait CounterContext: salsa::QueryContext { + fn clock(&self) -> &Counter; + fn log(&self) -> &Log; +} + +crate trait QueryContext: CounterContext { + salsa::query_prototype! { + fn memoized2() for Memoized2; + fn memoized1() for Memoized1; + fn volatile() for Volatile; + } +} + +salsa::query_definition! { + crate Memoized2(query: &impl QueryContext, (): ()) -> usize { + query.log().add("Memoized2 invoked"); + query.memoized1().of(()) + } +} + +salsa::query_definition! { + crate Memoized1(query: &impl QueryContext, (): ()) -> usize { + query.log().add("Memoized1 invoked"); + let v = query.volatile().of(()); + v / 3 + } +} + +salsa::query_definition! { + #[storage(volatile)] + crate Volatile(query: &impl QueryContext, (): ()) -> usize { + query.log().add("Volatile invoked"); + query.clock().increment() + } +} diff --git a/examples/incremental/tests.rs b/examples/incremental/tests.rs new file mode 100644 index 00000000..7648790c --- /dev/null +++ b/examples/incremental/tests.rs @@ -0,0 +1,23 @@ +#![cfg(test)] + +use crate::implementation::QueryContextImpl; +use crate::queries::CounterContext; +use crate::queries::QueryContext; + +impl QueryContextImpl { + fn assert_log(&self, expected_log: &[&str]) { + let expected_text = format!("{:#?}", expected_log); + let actual_text = format!("{:#?}", self.log().read()); + text_diff::assert_diff(&expected_text, &actual_text, "", 0); + } +} + +#[test] +fn foo() { + let query = QueryContextImpl::default(); + + // Invoking volatile twice will simply execute twice. + query.volatile().of(()); + query.volatile().of(()); + query.assert_log(&["Volatile invoked", "Volatile invoked"]); +} diff --git a/src/runtime.rs b/src/runtime.rs index 87db7489..53cc35e0 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -50,6 +50,24 @@ where &self.shared_state.storage } + /// Indicates that some input to the system has changed and hence + /// that memoized values **may** be invalidated. This cannot be + /// invoked while query computation is in progress. + /// + /// As a user of the system, you would not normally invoke this + /// method directly. Instead, you would use "input" queries and + /// invoke their `set` method. But it can be useful if you have a + /// "volatile" input that you must poll from time to time; in that + /// case, you can wrap the input with a "no-storage" query and + /// invoke this method from time to time. + pub fn next_revision(&self) { + if !self.local_state.borrow().query_stack.is_empty() { + panic!("next_revision invoked during a query computation"); + } + + self.increment_revision(); + } + /// Read current value of the revision counter. crate fn current_revision(&self) -> Revision { Revision {