Merge pull request #499 from camelid/input-mut
Some checks are pending
Book / Book (push) Waiting to run
Book / Deploy (push) Blocked by required conditions
Test / Test (false, beta) (push) Waiting to run
Test / Test (false, stable) (push) Waiting to run
Test / Test (true, nightly) (push) Waiting to run
Test / Miri (push) Waiting to run

book: Creating inputs no longer requires `&mut dyn Db`
This commit is contained in:
Niko Matsakis 2024-06-18 10:52:14 +00:00 committed by GitHub
commit 2c7cda5a8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 13 additions and 10 deletions

View file

@ -56,16 +56,18 @@ pub struct ProgramFile {
```
You create an input by using the `new` method.
Because the values of input fields are stored in the database, you also give an `&mut`-reference to the database:
Because the values of input fields are stored in the database, you also give an `&`-reference to the database:
```rust
let file: ProgramFile = ProgramFile::new(
&mut db,
&db,
PathBuf::from("some_path.txt"),
String::from("fn foo() { }"),
);
```
Mutable access is not needed since creating a new input cannot affect existing tracked data in the database.
### Salsa structs are just integers
The `ProgramFile` struct generated by the `salsa::input` macro doesn't actually store any data. It's just a newtyped integer id:
@ -111,7 +113,8 @@ file.data(&db)
### Writing input fields
Finally, you can also modify the value of an input field by using the setter method.
Since this is modifying the input, the setter takes an `&mut`-reference to the database:
Since this is modifying the input, and potentially invalidating data derived from it,
the setter takes an `&mut`-reference to the database:
```rust
file.set_contents(&mut db).to(String::from("fn foo() { /* add a comment */ }"));
@ -140,7 +143,7 @@ The algorithm Salsa uses to decide when a tracked function needs to be re-execut
Tracked functions have to follow a particular structure:
- They must take a `&`-reference to the database as their first argument.
- Note that because this is an `&`-reference, it is not possible to create or modify inputs during a tracked function!
- Note that because this is an `&`-reference, it is not possible to modify inputs during a tracked function!
- They must take a "Salsa struct" as the second argument -- in our example, this is an input struct, but there are other kinds of Salsa structs we'll describe shortly.
- They _can_ take additional arguments, but it's faster and better if they don't.

View file

@ -169,7 +169,7 @@ The reason we use a raw pointer in the struct is because instances of this struc
```rust
let mut db = MyDatabase::default();
let input = MyInput::new(&mut db, ...);
let input = MyInput::new(&db, ...);
// Revision 1:
let result1 = tracked_fn(&db, input);
@ -235,4 +235,4 @@ However in some later revision R2, how
### Freeing the memory while a tracked struct remains live
### Aliases of a tracked struct
### Aliases of a tracked struct

View file

@ -52,10 +52,10 @@ pub struct SourceProgram(salsa::Id);
```
It will also generate a method `new` that lets you create a `SourceProgram` in the database.
For an input, a `&mut db` reference is required, along with the values for each field:
For an input, a `&db` reference is required, along with the values for each field:
```rust
let source = SourceProgram::new(&mut db, "print 11 + 11".to_string());
let source = SourceProgram::new(&db, "print 11 + 11".to_string());
```
You can read the value of the field with `source.text(&db)`,
@ -90,7 +90,7 @@ then subsequent parts of the computation won't need to re-execute.
Apart from the fields being immutable, the API for working with a tracked struct is quite similar to an input:
* You can create a new value by using `new`, but with a tracked struct, you only need an `&dyn` database, not `&mut` (e.g., `Program::new(&db, some_staements)`)
* You can create a new value by using `new`: e.g., `Program::new(&db, some_statements)`
* You use a getter to read the value of a field, just like with an input (e.g., `my_func.statements(db)` to read the `statements` field).
* In this case, the field is tagged as `#[return_ref]`, which means that the getter will return a `&Vec<Statement>`, instead of cloning the vector.
@ -123,7 +123,7 @@ This would mean that we have to re-execute those parts of the code that depended
Apart from the fields being immutable, the API for working with a tracked struct is quite similar to an input:
* You can create a new value by using `new`, but with a tracked struct, you only need an `&dyn` database, not `&mut` (e.g., `Function::new(&db, some_name, some_args, some_body)`)
* You can create a new value by using `new`: e.g., `Function::new(&db, some_name, some_args, some_body)`
* You use a getter to read the value of a field, just like with an input (e.g., `my_func.args(db)` to read the `args` field).
### id fields