mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-12 16:35:21 +00:00
add a public next_revision
method and start on incremental test
This commit is contained in:
parent
1929b26505
commit
e134ffcdf4
8 changed files with 158 additions and 0 deletions
|
@ -13,3 +13,6 @@ derive-new = "0.5.5"
|
||||||
rustc-hash = "1.0"
|
rustc-hash = "1.0"
|
||||||
parking_lot = "0.6.4"
|
parking_lot = "0.6.4"
|
||||||
indexmap = "1.0.1"
|
indexmap = "1.0.1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
text-diff = "0.4.0"
|
14
examples/incremental/counter.rs
Normal file
14
examples/incremental/counter.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
crate struct Counter {
|
||||||
|
value: Cell<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Counter {
|
||||||
|
crate fn increment(&self) -> usize {
|
||||||
|
let v = self.value.get();
|
||||||
|
self.value.set(v + 1);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
36
examples/incremental/implementation.rs
Normal file
36
examples/incremental/implementation.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use crate::counter::Counter;
|
||||||
|
use crate::log::Log;
|
||||||
|
use crate::queries;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct QueryContextImpl {
|
||||||
|
runtime: salsa::runtime::Runtime<QueryContextImpl>,
|
||||||
|
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<QueryContextImpl> {
|
||||||
|
&self.runtime
|
||||||
|
}
|
||||||
|
}
|
16
examples/incremental/log.rs
Normal file
16
examples/incremental/log.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
crate struct Log {
|
||||||
|
data: RefCell<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Log {
|
||||||
|
crate fn add(&self, text: impl Into<String>) {
|
||||||
|
self.data.borrow_mut().push(text.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn read(&self) -> Vec<String> {
|
||||||
|
self.data.borrow().clone()
|
||||||
|
}
|
||||||
|
}
|
10
examples/incremental/main.rs
Normal file
10
examples/incremental/main.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#![feature(crate_visibility_modifier)]
|
||||||
|
#![feature(underscore_imports)]
|
||||||
|
|
||||||
|
mod counter;
|
||||||
|
mod implementation;
|
||||||
|
mod log;
|
||||||
|
mod queries;
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
fn main() {}
|
38
examples/incremental/queries.rs
Normal file
38
examples/incremental/queries.rs
Normal file
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
23
examples/incremental/tests.rs
Normal file
23
examples/incremental/tests.rs
Normal file
|
@ -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"]);
|
||||||
|
}
|
|
@ -50,6 +50,24 @@ where
|
||||||
&self.shared_state.storage
|
&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.
|
/// Read current value of the revision counter.
|
||||||
crate fn current_revision(&self) -> Revision {
|
crate fn current_revision(&self) -> Revision {
|
||||||
Revision {
|
Revision {
|
||||||
|
|
Loading…
Reference in a new issue