mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-07-07 13:25:17 +00:00
chore: Remove jar mentions from book (#775)
* Remove references to jar terminology * Update or remove invalid code links in book
This commit is contained in:
parent
2d4321e989
commit
9489764ad9
13 changed files with 10 additions and 336 deletions
|
@ -7,7 +7,6 @@
|
|||
- [Overview](./overview.md)
|
||||
- [Tutorial: calc language](./tutorial.md)
|
||||
- [Basic structure](./tutorial/structure.md)
|
||||
- [Jars and databases](./tutorial/jar.md)
|
||||
- [Defining the database struct](./tutorial/db.md)
|
||||
- [Defining the IR: the various "salsa structs"](./tutorial/ir.md)
|
||||
- [Defining the parser: memoized functions and inputs](./tutorial/parser.md)
|
||||
|
@ -28,7 +27,6 @@
|
|||
- [How Salsa works](./how_salsa_works.md)
|
||||
- [Videos](./videos.md)
|
||||
- [Plumbing](./plumbing.md)
|
||||
- [Jars and ingredients](./plumbing/jars_and_ingredients.md)
|
||||
- [Databases and runtime](./plumbing/database_and_runtime.md)
|
||||
- [The db lifetime on tracked/interned structs](./plumbing/db_lifetime.md)
|
||||
- [Tracked structures](./plumbing/tracked_structs.md)
|
||||
|
|
|
@ -7,7 +7,6 @@ We refer to this as the "plumbing".
|
|||
|
||||
The plumbing section is broken up into chapters:
|
||||
|
||||
- The [jars and ingredients](./plumbing/jars_and_ingredients.md) covers how each salsa item (like a tracked function) specifies what data it needs and runtime, and how links between items work.
|
||||
- The [database and runtime](./plumbing/database_and_runtime.md) covers the data structures that are used at runtime to coordinate workers, trigger cancellation, track which functions are active and what dependencies they have accrued, and so forth.
|
||||
- The [query operations](./plumbing/query_ops.md) chapter describes how the major operations on function ingredients work. This text was written for an older version of salsa but the logic is the same:
|
||||
- The [maybe changed after](./plumbing/maybe_changed_after.md) operation determines when a memoized value for a tracked function is out of date.
|
||||
|
|
|
@ -4,7 +4,7 @@ A salsa database struct is declared by the user with the `#[salsa::db]` annotati
|
|||
It contains all the data that the program needs to execute:
|
||||
|
||||
```rust,ignore
|
||||
#[salsa::db(jar0...jarn)]
|
||||
#[salsa::db]
|
||||
struct MyDatabase {
|
||||
storage: Storage<Self>,
|
||||
maybe_other_fields: u32,
|
||||
|
@ -28,12 +28,12 @@ The `Snapshot` method returns a `Snapshot<DB>` type, which prevents these clones
|
|||
The salsa `Storage` struct contains all the data that salsa itself will use and work with.
|
||||
There are three key bits of data:
|
||||
|
||||
- The `Shared` struct, which contains the data stored across all snapshots. This is primarily the ingredients described in the [jars and ingredients chapter](./jars_and_ingredients.md), but it also contains some synchronization information (a cond var). This is used for cancellation, as described below.
|
||||
- The `Shared` struct, which contains the data stored across all snapshots, such as synchronization information (a cond var). This is used for cancellation, as described below.
|
||||
- The data in the `Shared` struct is only shared across threads when other threads are active. Some operations, like mutating an input, require an `&mut` handle to the `Shared` struct. This is obtained by using the `Arc::get_mut` methods; obviously this is only possible when all snapshots and threads have ceased executing, since there must be a single handle to the `Arc`.
|
||||
- The `Routes` struct, which contains the information to find any particular ingredient -- this is also shared across all handles, and its construction is also described in the [jars and ingredients chapter](./jars_and_ingredients.md). The routes are separated out from the `Shared` struct because they are truly immutable at all times, and we want to be able to hold a handle to them while getting `&mut` access to the `Shared` struct.
|
||||
- The `Routes` struct, which contains the information to find any particular ingredient -- this is also shared across all handles. The routes are separated out from the `Shared` struct because they are truly immutable at all times, and we want to be able to hold a handle to them while getting `&mut` access to the `Shared` struct.
|
||||
- The `Runtime` struct, which is specific to a particular database instance. It contains the data for a single active thread, along with some links to shared data of its own.
|
||||
|
||||
## Incrementing the revision counter and getting mutable access to the jars
|
||||
## Incrementing the revision counter
|
||||
|
||||
Salsa's general model is that there is a single "master" copy of the database and, potentially, multiple snapshots.
|
||||
The snapshots are not directly owned, they are instead enclosed in a `Snapshot<DB>` type that permits only `&`-deref,
|
||||
|
@ -47,12 +47,6 @@ This allows us to get `&mut` access without any unsafe code and
|
|||
guarantees that we have successfully managed to cancel the other worker threads
|
||||
(or gotten ourselves into a deadlock).
|
||||
|
||||
The code to acquire `&mut` access to the database is the `jars_mut` method:
|
||||
|
||||
```rust
|
||||
{{#include ../../../src/storage.rs:jars_mut}}
|
||||
```
|
||||
|
||||
The key initial point is that it invokes `cancel_other_workers` before proceeding:
|
||||
|
||||
```rust
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
# Fetch
|
||||
|
||||
```rust,no_run,noplayground
|
||||
{{#include ../../../src/plumbing.rs:fetch}}
|
||||
```
|
||||
|
||||
The `fetch` operation computes the value of a query. It prefers to reuse memoized values when it can.
|
||||
|
||||
## Input queries
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
# Jars and ingredients
|
||||
|
||||
This page covers how data is organized in Salsa and how links between Salsa items (e.g., dependency tracking) work.
|
||||
|
||||
## Salsa items and ingredients
|
||||
|
||||
A **Salsa item** is some item annotated with a Salsa annotation that can be included in a jar.
|
||||
For example, a tracked function is a Salsa item:
|
||||
|
||||
```rust
|
||||
#[salsa::tracked]
|
||||
fn foo(db: &dyn Db, input: MyInput) { }
|
||||
```
|
||||
|
||||
...and so is a Salsa input...
|
||||
|
||||
```rust
|
||||
#[salsa::input]
|
||||
struct MyInput { }
|
||||
```
|
||||
|
||||
...or a tracked struct:
|
||||
|
||||
```rust
|
||||
#[salsa::tracked]
|
||||
struct MyStruct { }
|
||||
```
|
||||
|
||||
Each Salsa item needs certain bits of data at runtime to operate.
|
||||
These bits of data are called **ingredients**.
|
||||
Most Salsa items generate a single ingredient, but sometimes they make more than one.
|
||||
For example, a tracked function generates a [`FunctionIngredient`].
|
||||
A tracked struct, however, generates several ingredients, one for the struct itself (a [`TrackedStructIngredient`],
|
||||
and one [`FunctionIngredient`] for each value field.
|
||||
|
||||
[`FunctionIngredient`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/function.rs#L42
|
||||
[`TrackedStructIngredient`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/tracked_struct.rs#L18
|
||||
|
||||
### Ingredients define the core logic of Salsa
|
||||
|
||||
Most of the interesting Salsa code lives in these ingredients.
|
||||
For example, when you create a new tracked struct, the method [`TrackedStruct::new_struct`] is invoked;
|
||||
it is responsible for determining the tracked struct's id.
|
||||
Similarly, when you call a tracked function, that is translated into a call to [`TrackedFunction::fetch`],
|
||||
which decides whether there is a valid memoized value to return,
|
||||
or whether the function must be executed.
|
||||
|
||||
[`TrackedStruct::new_struct`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/tracked_struct.rs#L76
|
||||
[`TrackedFunction::fetch`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/function/fetch.rs#L15
|
||||
|
||||
### The `Ingredient` trait
|
||||
|
||||
Each ingredient implements the [`Ingredient<DB>`] trait, which defines generic operations supported by any kind of ingredient.
|
||||
For example, the method `maybe_changed_after` can be used to check whether some particular piece of data stored in the ingredient may have changed since a given revision:
|
||||
|
||||
[`Ingredient<DB>`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/ingredient.rs#L15
|
||||
[`maybe_changed_after`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/ingredient.rs#L21-L22
|
||||
|
||||
We'll see below that each database `DB` is able to take an `IngredientIndex` and use that to get an `&dyn Ingredient<DB>` for the corresponding ingredient.
|
||||
This allows the database to perform generic operations on an indexed ingredient without knowing exactly what the type of that ingredient is.
|
||||
|
||||
### Jars are a collection of ingredients
|
||||
|
||||
When you declare a Salsa jar, you list out each of the Salsa items that are included in that jar:
|
||||
|
||||
```rust,ignore
|
||||
#[salsa::jar]
|
||||
struct Jar(
|
||||
foo,
|
||||
MyInput,
|
||||
MyStruct
|
||||
);
|
||||
```
|
||||
|
||||
This expands to a struct like so:
|
||||
|
||||
```rust
|
||||
struct Jar(
|
||||
<foo as IngredientsFor>::Ingredient,
|
||||
<MyInput as IngredientsFor>::Ingredient,
|
||||
<MyStruct as IngredientsFor>::Ingredient,
|
||||
)
|
||||
```
|
||||
|
||||
The `IngredientsFor` trait is used to define the ingredients needed by some Salsa item, such as the tracked function `foo` or the tracked struct `MyInput`.
|
||||
Each Salsa item defines a type `I` so that `<I as IngredientsFor>::Ingredient` gives the ingredients needed by `I`.
|
||||
|
||||
### A database is a tuple of jars
|
||||
|
||||
Salsa's database storage ultimately boils down to a tuple of jar structs
|
||||
where each jar struct (as we just saw) itself contains the ingredients
|
||||
for the Salsa items within that jar.
|
||||
The database can thus be thought of as a list of ingredients,
|
||||
although that list is organized into a 2-level hierarchy.
|
||||
|
||||
The reason for this 2-level hierarchy is that it permits separate compilation and privacy.
|
||||
The crate that lists the jars doesn't have to know the contents of the jar to embed the jar struct in the database.
|
||||
And some of the types that appear in the jar may be private to another struct.
|
||||
|
||||
### The `HasJars` trait and the `Jars` type
|
||||
|
||||
Each Salsa database implements the `HasJars` trait,
|
||||
generated by the `salsa::db` procedural macro.
|
||||
The `HarJars` trait, among other things, defines a `Jars` associated type that maps to a tuple of the jars in the trait.
|
||||
|
||||
For example, given a database like this...
|
||||
|
||||
```rust,ignore
|
||||
#[salsa::db(Jar1, ..., JarN)]
|
||||
struct MyDatabase {
|
||||
storage: salsa::Storage<Self>
|
||||
}
|
||||
```
|
||||
|
||||
...the `salsa::db` macro would generate a `HasJars` impl that (among other things) contains `type Jars = (Jar1, ..., JarN)`:
|
||||
|
||||
```rust,ignore
|
||||
{{#include ../../../components/salsa-macros/src/db.rs:HasJars}}
|
||||
```
|
||||
|
||||
In turn, the `salsa::Storage<DB>` type ultimately contains a struct `Shared` that embeds `DB::Jars`, thus embedding all the data for each jar.
|
||||
|
||||
### Ingredient indices
|
||||
|
||||
During initialization, each ingredient in the database is assigned a unique index called the [`IngredientIndex`].
|
||||
This is a 32-bit number that identifies a particular ingredient from a particular jar.
|
||||
|
||||
[`IngredientIndex`]: https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/routes.rs#L5-L9
|
||||
|
||||
### Routes
|
||||
|
||||
In addition to an index, each ingredient in the database also has a corresponding _route_.
|
||||
A route is a closure that, given a reference to the `DB::Jars` tuple,
|
||||
returns a `&dyn Ingredient<DB>` reference.
|
||||
The route table allows us to go from the `IngredientIndex` for a particular ingredient
|
||||
to its `&dyn Ingredient<DB>` trait object.
|
||||
The route table is created while the database is being initialized,
|
||||
as described shortly.
|
||||
|
||||
### Database keys and dependency keys
|
||||
|
||||
A `DatabaseKeyIndex` identifies a specific value stored in some specific ingredient.
|
||||
It combines an [`IngredientIndex`] with a `key_index`, which is a `salsa::Id`:
|
||||
|
||||
```rust,ignore
|
||||
{{#include ../../../src/key.rs:DatabaseKeyIndex}}
|
||||
```
|
||||
|
||||
These kinds of indices are used to store connetions between ingredients.
|
||||
For example, each memoized value has to track its inputs.
|
||||
Those inputs are stored as dependency indices.
|
||||
We can then do things like ask, "did this input change since revision R?" by
|
||||
|
||||
- using the ingredient index to find the route and get a `&dyn Ingredient<DB>`
|
||||
- and then invoking the `maybe_changed_since` method on that trait object.
|
||||
|
||||
### `HasJarsDyn`
|
||||
|
||||
There is one catch in the above setup.
|
||||
The user's code always interacts with a `dyn crate::Db` value, where `crate::Db` is the trait defined by the jar; the `crate::Db` trait extends `salsa::HasJar` which in turn extends `salsa::Database`.
|
||||
Ideally, we would have `salsa::Database` extend `salsa::HasJars`, which is the main trait that gives access to the jars data.
|
||||
But we don't want to do that because `HasJars` defines an associated type `Jars`, and that would mean that every reference to `dyn crate::Db` would have to specify the jars type using something like `dyn crate::Db<Jars = J>`.
|
||||
This would be unergonomic, but what's worse, it would actually be impossible: the final Jars type combines the jars from multiple crates, and so it is not known to any individual jar crate.
|
||||
To workaround this, `salsa::Database` in fact extends _another_ trait, `HasJarsDyn`, that doesn't reveal the `Jars` or ingredient types directly, but just has various method that can be performed on an ingredient, given its `IngredientIndex`.
|
||||
Traits like `Ingredient<DB>` require knowing the full `DB` type.
|
||||
If we had one function ingredient directly invoke a method on `Ingredient<DB>`, that would imply that it has to be fully generic and only instantiated at the final crate, when the full database type is available.
|
||||
|
||||
We solve this via the `HasJarsDyn` trait. The `HasJarsDyn` trait exports a method that combines the "find ingredient, invoking method" steps into one method:
|
||||
|
||||
```rust,ignore aasaaasdfijjAasdfa
|
||||
{{#include ../../../src/storage.rs:HasJarsDyn}}
|
||||
```
|
||||
|
||||
So, technically, to check if an input has changed, an ingredient:
|
||||
|
||||
- Invokes `HasJarsDyn::maybe_changed_after` on the `dyn Database`
|
||||
- The impl for this method (generated by `#[salsa::db]`):
|
||||
- gets the route for the ingredient from the ingredient index
|
||||
- uses the route to get a `&dyn Ingredient`
|
||||
- invokes `maybe_changed_after` on that ingredient
|
||||
|
||||
### Initializing the database
|
||||
|
||||
The last thing to discuss is how the database is initialized.
|
||||
The `Default` implementation for `Storage<DB>` does the work:
|
||||
|
||||
```rust,ignore
|
||||
{{#include ../../../src/storage.rs:default}}
|
||||
```
|
||||
|
||||
First, it creates an empty `Routes` instance.
|
||||
Then it invokes the `DB::create_jars` method.
|
||||
The implementation of this method is defined by the `#[salsa::db]` macro; it invokes `salsa::plumbing::create_jars_inplace` to allocate memory for the jars, and then invokes the `Jar::init_jar` method on each of the jars to initialize them:
|
||||
|
||||
```rust,ignore
|
||||
{{#include ../../../components/salsa-macros/src/db.rs:create_jars}}
|
||||
```
|
||||
|
||||
This implementation for `init_jar` is generated by the `#[salsa::jar]` macro, and simply walks over the representative type for each salsa item and asks _it_ to create its ingredients
|
||||
|
||||
```rust,ignore
|
||||
{{#include ../../../components/salsa-macros/src/jar.rs:init_jar}}
|
||||
```
|
||||
|
||||
The code to create the ingredients for any particular item is generated by their associated macros (e.g., `#[salsa::tracked]`, `#[salsa::input]`), but it always follows a particular structure.
|
||||
To create an ingredient, we first invoke `Routes::push`, which creates the routes to that ingredient and assigns it an `IngredientIndex`.
|
||||
We can then invoke a function such as `FunctionIngredient::new` to create the structure.
|
||||
The _routes_ to an ingredient are defined as closures that, given the `DB::Jars`, can find the data for a particular ingredient.
|
|
@ -1,9 +1,5 @@
|
|||
# Maybe changed after
|
||||
|
||||
```rust,no_run,noplayground
|
||||
{{#include ../../../src/plumbing.rs:maybe_changed_after}}
|
||||
```
|
||||
|
||||
The `maybe_changed_after` operation computes whether a query's value *may have changed* **after** the given revision. In other words, `Q.maybe_change_since(R)` is true if the value of the query `Q` may have changed in the revisions `(R+1)..R_now`, where `R_now` is the current revision. Note that it doesn't make sense to ask `maybe_changed_after(R_now)`.
|
||||
|
||||
## Input queries
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
# Query operations
|
||||
|
||||
Each of the query storage struct implements the `QueryStorageOps` trait found in the [`plumbing`] module:
|
||||
|
||||
```rust,no_run,noplayground
|
||||
{{#include ../../../src/plumbing.rs:QueryStorageOps}}
|
||||
```
|
||||
|
||||
which defines the basic operations that all queries support. The most important are these two:
|
||||
The most important basic operations that all queries support are:
|
||||
|
||||
* [maybe changed after](./maybe_changed_after.md): Returns true if the value of the query (for the given key) may have changed since the given revision.
|
||||
* [Fetch](./fetch.md): Returns the up-to-date value for the given K (or an error in the case of an "unrecovered" cycle).
|
||||
|
||||
[`plumbing`]: https://github.com/salsa-rs/salsa/blob/master/src/plumbing.rs
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# Ingredient
|
||||
|
||||
An *ingredient* is an individual piece of storage used to create a [salsa item](./salsa_item.md)
|
||||
See the [jars and ingredients](../jars_and_ingredients.md) chapter for more details.
|
||||
An *ingredient* is an individual piece of storage used to create a [salsa item](./salsa_item.md)
|
|
@ -1,4 +1,3 @@
|
|||
# Salsa item
|
||||
|
||||
A salsa item is something that is decorated with a `#[salsa::foo]` macro, like a tracked function or struct.
|
||||
See the [jars and ingredients](../jars_and_ingredients.md) chapter for more details.
|
||||
A salsa item is something that is decorated with a `#[salsa::foo]` macro, like a tracked function or struct.
|
|
@ -1,7 +1,6 @@
|
|||
# Defining the database struct
|
||||
|
||||
Now that we have defined a [jar](./jar.md), we need to create the **database struct**.
|
||||
The database struct is where all the jars come together.
|
||||
First, we need to create the **database struct**.
|
||||
Typically it is only used by the "driver" of your application;
|
||||
the one which starts up the program, supplies the inputs, and relays the outputs.
|
||||
|
||||
|
@ -13,11 +12,8 @@ In `calc`, the database struct is in the [`db`] module, and it looks like this:
|
|||
{{#include ../../../examples/calc/db.rs:db_struct}}
|
||||
```
|
||||
|
||||
The `#[salsa::db(...)]` attribute takes a list of all the jars to include.
|
||||
The struct must have a field named `storage` whose type is `salsa::Storage<Self>`, but it can also contain whatever other fields you want.
|
||||
The `storage` struct owns all the data for the jars listed in the `db` attribute.
|
||||
|
||||
The `salsa::db` attribute autogenerates a bunch of impls for things like the `salsa::HasJar<crate::Jar>` trait that we saw earlier.
|
||||
The `#[salsa::db]` attribute marks the struct as a database.
|
||||
It must have a field named `storage` whose type is `salsa::Storage<Self>`, but it can also contain whatever other fields you want.
|
||||
|
||||
## Implementing the `salsa::Database` trait
|
||||
|
||||
|
@ -34,11 +30,3 @@ If you want to permit accessing your database from multiple threads at once, the
|
|||
```rust
|
||||
{{#include ../../../examples/calc/db.rs:par_db_impl}}
|
||||
```
|
||||
|
||||
## Implementing the traits for each jar
|
||||
|
||||
The `Database` struct also needs to implement the [database traits for each jar](./jar.md#database-trait-for-the-jar).
|
||||
In our case, though, we already wrote that impl as a [blanket impl alongside the jar itself](./jar.md#implementing-the-database-trait-for-the-jar),
|
||||
so no action is needed.
|
||||
This is the recommended strategy unless your trait has custom members that depend on fields of the `Database` itself
|
||||
(for example, sometimes the `Database` holds some kind of custom resource that you want to give access to).
|
||||
|
|
|
@ -17,9 +17,6 @@ All Salsa structs store the actual values of their fields in the Salsa database.
|
|||
This permits us to track when the values of those fields change to figure out what work will need to be re-executed.
|
||||
|
||||
When you annotate a struct with one of the above Salsa attributes, Salsa actually generates a bunch of code to link that struct into the database.
|
||||
This code must be connected to some [jar](./jar.md).
|
||||
By default, this is `crate::Jar`, but you can specify a different jar with the `jar=` attribute (e.g., `#[salsa::input(jar = MyJar)]`).
|
||||
You must also list the struct in the jar definition itself, or you will get errors.
|
||||
|
||||
## Input structs
|
||||
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
# Jars and databases
|
||||
|
||||
Before we can define the interesting parts of our Salsa program, we have to setup a bit of structure that defines the Salsa **database**.
|
||||
The database is a struct that ultimately stores all of Salsa's intermediate state, such as the memoized return values from [tracked functions].
|
||||
|
||||
[tracked functions]: ../overview.md#tracked-functions
|
||||
|
||||
The database itself is defined in terms of intermediate structures, called **jars**[^jar], which themselves contain the data for each function.
|
||||
This setup allows Salsa programs to be divided amongst many crates.
|
||||
Typically, you define one jar struct per crate, and then when you construct the final database, you simply list the jar structs.
|
||||
This permits the crates to define private functions and other things that are members of the jar struct, but not known directly to the database.
|
||||
|
||||
[^jar]: Jars of salsa -- get it? Get it??[^java]
|
||||
|
||||
[^java]: OK, maybe it also brings to mind Java `.jar` files, but there's no real relationship. A jar is just a Rust struct, not a packaging format.
|
||||
|
||||
## Defining a jar struct
|
||||
|
||||
To define a jar struct, you create a tuple struct with the `#[salsa::jar]` annotation:
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/calc/main.rs:jar_struct}}
|
||||
```
|
||||
|
||||
Although it's not required, it's highly recommended to put the `jar` struct at the root of your crate, so that it can be referred to as `crate::Jar`.
|
||||
All of the other Salsa annotations reference a jar struct, and they all default to the path `crate::Jar`.
|
||||
If you put the jar somewhere else, you will have to override that default.
|
||||
|
||||
## Defining the database trait
|
||||
|
||||
The `#[salsa::jar]` annotation also includes a `db = Db` field.
|
||||
The value of this field (normally `Db`) is the name of a trait that represents the database.
|
||||
Salsa programs never refer _directly_ to the database; instead, they take a `&dyn Db` argument.
|
||||
This allows for separate compilation, where you have a database that contains the data for two jars, but those jars don't depend on one another.
|
||||
|
||||
The database trait for our `calc` crate is very simple:
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/calc/main.rs:jar_db}}
|
||||
```
|
||||
|
||||
When you define a database trait like `Db`, the one thing that is required is that it must have a supertrait `salsa::DbWithJar<Jar>`,
|
||||
where `Jar` is the jar struct. If your jar depends on other jars, you can have multiple such supertraits (e.g., `salsa::DbWithJar<other_crate::Jar>`).
|
||||
|
||||
Typically the `Db` trait has no other members or supertraits, but you are also free to add whatever other things you want in the trait.
|
||||
When you define your final database, it will implement the trait, and you can then define the implementation of those other things.
|
||||
This allows you to create a way for your jar to request context or other info from the database that is not moderated through Salsa,
|
||||
should you need that.
|
||||
|
||||
## Implementing the database trait for the jar
|
||||
|
||||
The `Db` trait must be implemented by the database struct.
|
||||
We're going to define the database struct in a [later section](./db.md),
|
||||
and one option would be to simply implement the jar `Db` trait there.
|
||||
However, since we don't define any custom logic in the trait,
|
||||
a common choice is to write a blanket impl for any type that implements `DbWithJar<Jar>`,
|
||||
and that's what we do here:
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/calc/main.rs:jar_db_impl}}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
If the concept of a jar seems a bit abstract to you, don't overthink it. The TL;DR is that when you create a Salsa program, you need to perform the following steps:
|
||||
|
||||
- In each of your crates:
|
||||
- Define a `#[salsa::jar(db = Db)]` struct, typically at `crate::Jar`, and list each of your various Salsa-annotated things inside of it.
|
||||
- Define a `Db` trait, typically at `crate::Db`, that you will use in memoized functions and elsewhere to refer to the database struct.
|
||||
- Once, typically in your final crate:
|
||||
- Define a database `D`, as described in the [next section](./db.md), that will contain a list of each of the jars for each of your crates.
|
||||
- Implement the `Db` traits for each jar for your database type `D` (often we do this through blanket impls in the jar crates).
|
|
@ -50,12 +50,8 @@ Setting up a scheme like this is relatively easy in Salsa and uses the same prin
|
|||
### Parameters to a tracked function
|
||||
|
||||
The **first** parameter to a tracked function is **always** the database, `db: &dyn crate::Db`.
|
||||
It must be a `dyn` value of whatever database is associated with the jar.
|
||||
|
||||
The **second** parameter to a tracked function is **always** some kind of Salsa struct.
|
||||
The first parameter to a memoized function is always the database,
|
||||
which should be a `dyn Trait` value for the database trait associated with the jar
|
||||
(the default jar is `crate::Jar`).
|
||||
|
||||
Tracked functions may take other arguments as well, though our examples here do not.
|
||||
Functions that take additional arguments are less efficient and flexible.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue