clarify jars a bit, hopefully

Some folks were thinking that Jars were something
more complex than they are.
This commit is contained in:
Niko Matsakis 2022-08-02 07:57:23 +03:00
parent 6bd6f6ee0b
commit 8e348f0bc8

View file

@ -1,21 +1,23 @@
# Jars and databases
Salsa programs are composed in **jars**[^jar].
A **jar** is the salsa version of a Rust crate or module.
It is a struct that contains the memoized results for some subset of your program.
A jar is just a fancy name for a struct whose fields contain the hashmaps and other state required to implement salsa concepts like [memoized function](../overview.md#memoized-functions) or [entity](../overview.md#entity-values)/[interned](../overview.md#interned-values) structs.
Typically you have one jar per crate, but that is not required.
When you declare the salsa database, you will give it a list of all the jar structs in your program, and it will allocate one of each so as to have all the storage it needs.
Typically you define one jar per crate in your program, and you define it at the path `crate::Jar`.
You don't have to do this, but it's more convenient because the various salsa macros have defaults that expect the jar to be at this location.
Each time you declare something like a [memoized function], it is associated with some jar.
By default, that jar is expected to be `crate::Jar`.
You can give the jar struct another name, or put it somewhere else, but then you will have to write `jar = path::to::your::Jar` everywhere, so it's not recommended.
Our `calc` example has only a single crate, but we'll still put the `Jar` struct at the root of the crate:
Our `calc` example has only a single crate. We follow the salsa convention and declare the `Jar` struct at the root of the crate:
```rust
{{#include ../../../calc-example/calc/src/main.rs:jar_struct}}
```
The `#[salsa::jar]` annotation indicates that this struct is a Salsa jar.
The struct must be a tuple struct, and the fields in the struct correspond to the salsa [memoized functions], [entities], and other concepts that we are going to introduce in this tutorial.
The idea is that the field type will contain the storage needed to implement that particular salsa-ized thing.
You can see that a jar is just a tuple struct, but annotated with `#[salsa::Jar]`.
The fields of the struct correspond to the various things that need state in the database.
We're going to be introducing each of those fields through the tutorial.
[memoized functions]: ../reference/memoized.md
[entities]: ../reference/entity.md
@ -31,8 +33,8 @@ It identifies the **database trait** for this jar.
Whereas a salsa jar contains all the storage needed for a particular crate,
the salsa **database** is a struct that contains all the storage needed for an entire program.
Jars, however, don't refer directly to this database struct.
Instead, each jar defines a trait, typically called `Db`, that the struct must implement.
Typical salsa functions, however, don't refer directly to this database struct.
Instead, they refer to a trait, typically called `crate::Db`, that the final database must implement.
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:
@ -61,3 +63,14 @@ and that's what we do here:
```rust
{{#include ../../../calc-example/calc/src/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 do:
- 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).