mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-22 21:05:11 +00:00
Merge #362
362: Implement Setter API r=XFFXFF a=crlf0710 Fixes #329 Co-authored-by: Charles Lew <crlf0710@gmail.com>
This commit is contained in:
commit
e1f162742d
19 changed files with 74 additions and 32 deletions
|
@ -114,7 +114,9 @@ fn check_string(
|
|||
|
||||
// Apply edits and check diagnostics/logs after each one
|
||||
for (new_source_text, expected_diagnostics, expected_logs) in edits {
|
||||
source_program.set_text(&mut db, new_source_text.to_string());
|
||||
source_program
|
||||
.set_text(&mut db)
|
||||
.to(new_source_text.to_string());
|
||||
let program = parse_statements(&db, source_program);
|
||||
expected_diagnostics.assert_debug_eq(&type_check_program::accumulated::<Diagnostics>(
|
||||
&db, program,
|
||||
|
|
|
@ -94,11 +94,11 @@ impl InputStruct {
|
|||
let set_field_names = self.all_set_field_names();
|
||||
let field_setters: Vec<syn::ImplItemMethod> = field_indices.iter().zip(&set_field_names).zip(&field_tys).map(|((field_index, set_field_name), field_ty)| {
|
||||
parse_quote! {
|
||||
pub fn #set_field_name<'db>(self, __db: &'db mut #db_dyn_ty, __value: #field_ty) -> #field_ty
|
||||
pub fn #set_field_name<'db>(self, __db: &'db mut #db_dyn_ty) -> salsa::setter::Setter<'db, #ident, #field_ty>
|
||||
{
|
||||
let (__jar, __runtime) = <_ as salsa::storage::HasJar<#jar_ty>>::jar_mut(__db);
|
||||
let __ingredients = <#jar_ty as salsa::storage::HasIngredientsFor< #ident >>::ingredient_mut(__jar);
|
||||
__ingredients.#field_index.store(__runtime, self, __value, salsa::Durability::LOW).unwrap()
|
||||
salsa::setter::Setter::new(__runtime, self, &mut __ingredients.#field_index)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -426,7 +426,7 @@ fn setter_fn(
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// #[salsa::tracked(lru=32)]
|
||||
/// fn my_tracked_fn(db: &dyn crate::Db, ...) { }
|
||||
///
|
||||
|
|
|
@ -20,6 +20,7 @@ pub mod revision;
|
|||
pub mod routes;
|
||||
pub mod runtime;
|
||||
pub mod salsa_struct;
|
||||
pub mod setter;
|
||||
pub mod storage;
|
||||
#[doc(hidden)]
|
||||
pub mod tracked_struct;
|
||||
|
|
39
components/salsa-2022/src/setter.rs
Normal file
39
components/salsa-2022/src/setter.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use crate::input_field::InputFieldIngredient;
|
||||
use crate::{AsId, Durability, Runtime};
|
||||
use std::hash::Hash;
|
||||
|
||||
#[must_use]
|
||||
pub struct Setter<'setter, K, F> {
|
||||
runtime: &'setter mut Runtime,
|
||||
key: K,
|
||||
ingredient: &'setter mut InputFieldIngredient<K, F>,
|
||||
durability: Durability,
|
||||
}
|
||||
|
||||
impl<'setter, K, F> Setter<'setter, K, F>
|
||||
where
|
||||
K: Eq + Hash + AsId,
|
||||
{
|
||||
pub fn new(
|
||||
runtime: &'setter mut Runtime,
|
||||
key: K,
|
||||
ingredient: &'setter mut InputFieldIngredient<K, F>,
|
||||
) -> Self {
|
||||
Setter {
|
||||
runtime,
|
||||
key,
|
||||
ingredient,
|
||||
durability: Durability::LOW,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_durability(self, durability: Durability) -> Self {
|
||||
Setter { durability, ..self }
|
||||
}
|
||||
|
||||
pub fn to(self, value: F) -> F {
|
||||
self.ingredient
|
||||
.store(self.runtime, self.key, value, self.durability)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
|
@ -81,7 +81,7 @@ fn test1() {
|
|||
"#]]
|
||||
.assert_debug_eq(&compute::accumulated::<Integers>(&db, l1));
|
||||
|
||||
l0.set_value(&mut db, 2);
|
||||
l0.set_value(&mut db).to(2);
|
||||
compute(&db, l1);
|
||||
expect![[r#"
|
||||
[
|
||||
|
|
|
@ -87,7 +87,7 @@ fn test1() {
|
|||
// When we mutate `l1`, we should re-execute `compute` for `l1`,
|
||||
// and we re-execute accumulated for `l1`, but we do NOT re-execute
|
||||
// `compute` for `l2`.
|
||||
l1.set_value(&mut db, 2);
|
||||
l1.set_value(&mut db).to(2);
|
||||
assert_eq!(compute(&db, l2), 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -82,7 +82,7 @@ fn test1() {
|
|||
// but we should not have to re-execute `compute` for `l2`.
|
||||
// The only inpout for `compute(l1)` is the accumulated values from `l1`,
|
||||
// which have not changed.
|
||||
l1.set_value(&mut db, 2);
|
||||
l1.set_value(&mut db).to(2);
|
||||
assert_eq!(compute(&db, l2), 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -132,7 +132,7 @@ fn change_a_and_reaccumulate() {
|
|||
]"#]]);
|
||||
|
||||
// Change to `a = 1`, which means `push_logs` does not call `push_a_logs` at all
|
||||
input.set_field_a(&mut db, 1);
|
||||
input.set_field_a(&mut db).to(1);
|
||||
let logs = push_logs::accumulated::<Logs>(&db, input);
|
||||
expect![[r#"
|
||||
[
|
||||
|
@ -167,7 +167,7 @@ fn get_a_logs_after_changing_b() {
|
|||
|
||||
// Changing `b` does not cause `push_a_logs` to re-execute
|
||||
// and we still get the same result
|
||||
input.set_field_b(&mut db, 5);
|
||||
input.set_field_b(&mut db).to(5);
|
||||
let logs = push_a_logs::accumulated::<Logs>(&db, input);
|
||||
expect![[r#"
|
||||
[
|
||||
|
|
|
@ -248,7 +248,7 @@ fn cycle_revalidate() {
|
|||
let mut db = Database::default();
|
||||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
abc.set_b(&mut db, CycleQuery::A); // same value as default
|
||||
abc.set_b(&mut db).to(CycleQuery::A); // same value as default
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ fn cycle_recovery_unchanged_twice() {
|
|||
let abc = ABC::new(&mut db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
||||
abc.set_c(&mut db, CycleQuery::A); // force new revision
|
||||
abc.set_c(&mut db).to(CycleQuery::A); // force new revision
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ fn cycle_appears() {
|
|||
// A --> B
|
||||
// ^ |
|
||||
// +-----+
|
||||
abc.set_b(&mut db, CycleQuery::A);
|
||||
abc.set_b(&mut db).to(CycleQuery::A);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ fn cycle_disappears() {
|
|||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
||||
// A --> B
|
||||
abc.set_b(&mut db, CycleQuery::None);
|
||||
abc.set_b(&mut db).to(CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_ok());
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ fn basic() {
|
|||
// * the struct's field
|
||||
// * the `copy_field` result
|
||||
|
||||
input.set_field(&mut db, 2);
|
||||
input.set_field(&mut db).to(2);
|
||||
assert_eq!(final_result(&db, input), 1 * 2 + 0 * 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -103,7 +103,7 @@ fn basic() {
|
|||
// * the struct itself
|
||||
// * the struct's field
|
||||
// * the `contribution_from_struct` result
|
||||
input.set_field(&mut db, 2);
|
||||
input.set_field(&mut db).to(2);
|
||||
assert_eq!(final_result(&db, input), 1 * 2 + 0 * 2);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -91,7 +91,7 @@ fn execute() {
|
|||
"final_result_depends_on_y(MyInput(Id { value: 1 }))",
|
||||
]"#]]);
|
||||
|
||||
input.set_field(&mut db, 23);
|
||||
input.set_field(&mut db).to(23);
|
||||
// x = (23 + 1) / 2 = 12
|
||||
// Intermediate result x changes, so final result depends on x
|
||||
// needs to be recomputed;
|
||||
|
|
|
@ -70,7 +70,7 @@ fn execute() {
|
|||
"result_depends_on_y(MyInput(Id { value: 1 }))",
|
||||
]"#]]);
|
||||
|
||||
input.set_x(&mut db, 23);
|
||||
input.set_x(&mut db).to(23);
|
||||
// input x changes, so result depends on x needs to be recomputed;
|
||||
assert_eq!(result_depends_on_x(&db, input), 24);
|
||||
db.assert_logs(expect![[r#"
|
||||
|
|
|
@ -68,14 +68,14 @@ fn execute() {
|
|||
|
||||
// Intermediate result is the same, so final result does
|
||||
// not need to be recomputed:
|
||||
input.set_field(&mut db, 23);
|
||||
input.set_field(&mut db).to(23);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
"intermediate_result(MyInput(Id { value: 1 }))",
|
||||
]"#]]);
|
||||
|
||||
input.set_field(&mut db, 24);
|
||||
input.set_field(&mut db).to(24);
|
||||
assert_eq!(final_result(&db, input), 24);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -101,7 +101,7 @@ fn red_herring() {
|
|||
// This will trigger a new revision in the database
|
||||
// but shouldn't actually invalidate our existing ones.
|
||||
let input2 = MyInput::new(&mut db, 44);
|
||||
input2.set_field(&mut db, 66);
|
||||
input2.set_field(&mut db).to(66);
|
||||
|
||||
// Re-run the query on the original input. Nothing re-executes!
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
|
|
@ -44,12 +44,12 @@ fn execute() {
|
|||
|
||||
// Overwrite field with an empty String
|
||||
// and store the old value in my_string
|
||||
let mut my_string = input.set_field(&mut db, String::new());
|
||||
let mut my_string = input.set_field(&mut db).to(String::new());
|
||||
my_string.push_str(" World!");
|
||||
|
||||
// Set the field back to out initial String,
|
||||
// expecting to get the empty one back
|
||||
assert_eq!(input.set_field(&mut db, my_string), "");
|
||||
assert_eq!(input.set_field(&mut db).to(my_string), "");
|
||||
|
||||
// Check if the stored String is the one we expected
|
||||
assert_eq!(input.field(&db), "Hello World!");
|
||||
|
|
|
@ -27,7 +27,7 @@ impl MyInput {
|
|||
}
|
||||
|
||||
pub fn set_field(self, db: &mut dyn Db, id: String) {
|
||||
self.set_text(db, id);
|
||||
self.set_text(db).to(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ fn test_run_0_then_5_then_20() {
|
|||
//
|
||||
// * `create_tracked` does re-execute, but specifies same value for `maybe_specified` as before
|
||||
// * `read_maybe_specified` does not re-execute (its input has not changed)
|
||||
input.set_field(&mut db, 5);
|
||||
input.set_field(&mut db).to(5);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -226,7 +226,7 @@ fn test_run_0_then_5_then_20() {
|
|||
// * `create_tracked` re-executes but does not specify any value
|
||||
// * `read_maybe_specified` is invoked and it calls `maybe_specified`, which now executes
|
||||
// (its value has not been specified)
|
||||
input.set_field(&mut db, 20);
|
||||
input.set_field(&mut db).to(20);
|
||||
assert_eq!(final_result(&db, input), 200);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -278,7 +278,7 @@ fn test_run_0_then_5_then_10_then_20() {
|
|||
//
|
||||
// * `create_tracked` does re-execute, but specifies same value for `maybe_specified` as before
|
||||
// * `read_maybe_specified` does not re-execute (its input has not changed)
|
||||
input.set_field(&mut db, 5);
|
||||
input.set_field(&mut db).to(5);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -297,7 +297,7 @@ fn test_run_0_then_5_then_10_then_20() {
|
|||
// * `create_tracked` does re-execute and specifies no value for `maybe_specified`
|
||||
// * `maybe_specified_value` returns 10; this is the same value as was specified.
|
||||
// * `read_maybe_specified` therefore does NOT need to execute.
|
||||
input.set_field(&mut db, 10);
|
||||
input.set_field(&mut db).to(10);
|
||||
assert_eq!(final_result(&db, input), 100);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -318,7 +318,7 @@ fn test_run_0_then_5_then_10_then_20() {
|
|||
// Set input to 20:
|
||||
//
|
||||
// * Everything re-executes to get new result (200).
|
||||
input.set_field(&mut db, 20);
|
||||
input.set_field(&mut db).to(20);
|
||||
assert_eq!(final_result(&db, input), 200);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -362,7 +362,7 @@ fn test_run_5_then_20() {
|
|||
"Event { runtime_id: RuntimeId { counter: 0 }, kind: WillCheckCancellation }",
|
||||
]"#]]);
|
||||
|
||||
input.set_field(&mut db, 20);
|
||||
input.set_field(&mut db).to(20);
|
||||
assert_eq!(final_result(&db, input), 200);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
|
|
@ -69,14 +69,14 @@ fn one_entity() {
|
|||
|
||||
// Intermediate result is the same, so final result does
|
||||
// not need to be recomputed:
|
||||
input.set_field(&mut db, 23);
|
||||
input.set_field(&mut db).to(23);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
"intermediate_result(MyInput(Id { value: 1 }))",
|
||||
]"#]]);
|
||||
|
||||
input.set_field(&mut db, 24);
|
||||
input.set_field(&mut db).to(24);
|
||||
assert_eq!(final_result(&db, input), 24);
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
|
@ -102,7 +102,7 @@ fn red_herring() {
|
|||
// This will trigger a new revision in the database
|
||||
// but shouldn't actually invalidate our existing ones.
|
||||
let input2 = MyInput::new(&mut db, 44);
|
||||
input2.set_field(&mut db, 66);
|
||||
input2.set_field(&mut db).to(66);
|
||||
|
||||
// Re-run the query on the original input. Nothing re-executes!
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
|
Loading…
Reference in a new issue