<buttonid="sidebar-toggle"class="icon-button"type="button"title="Toggle Table of Contents"aria-label="Toggle Table of Contents"aria-controls="sidebar">
<ahref="../print.html"title="Print this book"aria-label="Print this book">
<iid="print-button"class="fa fa-print"></i>
</a>
</div>
</div>
<divid="search-wrapper"class="hidden">
<formid="searchbar-outer"class="searchbar-outer">
<inputtype="search"id="searchbar"name="searchbar"placeholder="Search this book ..."aria-controls="searchresults-outer"aria-describedby="searchresults-header">
<h1id="jars-and-ingredients"><aclass="header"href="#jars-and-ingredients">Jars and ingredients</a></h1>
<blockquote>
<p>⚠️ <strong>IN-PROGRESS VERSION OF SALSA.</strong> ⚠️</p>
<p>This page describes the unreleased "Salsa 2022" version, which is a major departure from older versions of salsa. The code here works but is only available on github and from the <code>salsa-2022</code> crate.</p>
For example, a tracked function generates a <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/function.rs#L42"><code>FunctionIngredient</code></a>.
A tracked struct, however, generates several ingredients, one for the struct itself (a <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/tracked_struct.rs#L18"><code>TrackedStructIngredient</code></a>,
and one <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/function.rs#L42"><code>FunctionIngredient</code></a> for each value field.</p>
<h3id="ingredients-define-the-core-logic-of-salsa"><aclass="header"href="#ingredients-define-the-core-logic-of-salsa">Ingredients define the core logic of Salsa</a></h3>
<p>Most of the interesting Salsa code lives in these ingredients.
For example, when you create a new tracked struct, the method <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/tracked_struct.rs#L76"><code>TrackedStruct::new_struct</code></a> 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 <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/function/fetch.rs#L15"><code>TrackedFunction::fetch</code></a>,
which decides whether there is a valid memoized value to return,
<p>Each ingredient implements the <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/ingredient.rs#L15"><code>Ingredient<DB></code></a> trait, which defines generic operations supported by any kind of ingredient.
For example, the method <code>maybe_changed_after</code> can be used to check whether some particular piece of data stored in the ingredient may have changed since a given revision:</p>
<p>We'll see below that each database <code>DB</code> is able to take an <code>IngredientIndex</code> and use that to get an <code>&dyn Ingredient<DB></code> 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.</p>
<h3id="jars-are-a-collection-of-ingredients"><aclass="header"href="#jars-are-a-collection-of-ingredients">Jars are a collection of ingredients</a></h3>
<p>The <code>IngredientsFor</code> trait is used to define the ingredients needed by some Salsa item, such as the tracked function <code>foo</code> or the tracked struct <code>MyInput</code>.
Each Salsa item defines a type <code>I</code> so that <code><I as IngredientsFor>::Ingredient</code> gives the ingredients needed by <code>I</code>.</p>
<h3id="a-database-is-a-tuple-of-jars"><aclass="header"href="#a-database-is-a-tuple-of-jars">A database is a tuple of jars</a></h3>
<p>Salsa's database storage ultimately boils down to a tuple of jar structs
<h3id="the-hasjars-trait-and-the-jars-type"><aclass="header"href="#the-hasjars-trait-and-the-jars-type">The <code>HasJars</code> trait and the <code>Jars</code> type</a></h3>
<p>Each Salsa database implements the <code>HasJars</code> trait,
<p>...the <code>salsa::db</code> macro would generate a <code>HasJars</code> impl that (among other things) contains <code>type Jars = (Jar1, ..., JarN)</code>:</p>
<pre><codeclass="language-rust ignore"> impl salsa::storage::HasJars for #db {
type Jars = (#(#jar_paths,)*);
</code></pre>
<p>In turn, the <code>salsa::Storage<DB></code> type ultimately contains a struct <code>Shared</code> that embeds <code>DB::Jars</code>, thus embedding all the data for each jar.</p>
<p>During initialization, each ingredient in the database is assigned a unique index called the <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/routes.rs#L5-L9"><code>IngredientIndex</code></a>.
This is a 32-bit number that identifies a particular ingredient from a particular jar.</p>
<p>In addition to an index, each ingredient in the database also has a corresponding <em>route</em>.
A route is a closure that, given a reference to the <code>DB::Jars</code> tuple,
returns a <code>&dyn Ingredient<DB></code> reference.
The route table allows us to go from the <code>IngredientIndex</code> for a particular ingredient
to its <code>&dyn Ingredient<DB></code> trait object.
The route table is created while the database is being initialized,
as described shortly.</p>
<h3id="database-keys-and-dependency-keys"><aclass="header"href="#database-keys-and-dependency-keys">Database keys and dependency keys</a></h3>
<p>A <code>DatabaseKeyIndex</code> identifies a specific value stored in some specific ingredient.
It combines an <ahref="https://github.com/salsa-rs/salsa/blob/becaade31e6ebc58cd0505fc1ee4b8df1f39f7de/components/salsa-2022/src/routes.rs#L5-L9"><code>IngredientIndex</code></a> with a <code>key_index</code>, which is a <code>salsa::Id</code>:</p>
<pre><codeclass="language-rust ignore">/// An "active" database key index represents a database key index
/// that is actively executing. In that case, the `key_index` cannot be
The user's code always interacts with a <code>dyn crate::Db</code> value, where <code>crate::Db</code> is the trait defined by the jar; the <code>crate::Db</code> trait extends <code>salsa::HasJar</code> which in turn extends <code>salsa::Database</code>.
Ideally, we would have <code>salsa::Database</code> extend <code>salsa::HasJars</code>, which is the main trait that gives access to the jars data.
But we don't want to do that because <code>HasJars</code> defines an associated type <code>Jars</code>, and that would mean that every reference to <code>dyn crate::Db</code> would have to specify the jars type using something like <code>dyn crate::Db<Jars = J></code>.
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, <code>salsa::Database</code> in fact extends <em>another</em> trait, <code>HasJarsDyn</code>, that doesn't reveal the <code>Jars</code> or ingredient types directly, but just has various method that can be performed on an ingredient, given its <code>IngredientIndex</code>.
Traits like <code>Ingredient<DB></code> require knowing the full <code>DB</code> type.
If we had one function ingredient directly invoke a method on <code>Ingredient<DB></code>, that would imply that it has to be fully generic and only instantiated at the final crate, when the full database type is available.</p>
<p>We solve this via the <code>HasJarsDyn</code> trait. The <code>HasJarsDyn</code> trait exports a method that combines the "find ingredient, invoking method" steps into one method:</p>
<p>First, it creates an empty <code>Routes</code> instance.
Then it invokes the <code>DB::create_jars</code> method.
The implementation of this method is defined by the <code>#[salsa::db]</code> macro; it simply invokes the <code>Jar::create_jar</code> method on each of the jars:</p>
<p>This implementation for <code>create_jar</code> is geneated by the <code>#[salsa::jar]</code> macro, and simply walks over the representative type for each salsa item and asks <em>it</em> to create its ingredients</p>
</span> let #field_var_names = <#field_tys as salsa::storage::IngredientsFor>::create_ingredients(routes);
)*
Self(#(#field_var_names),*)
}
}
}
</code></pre>
<p>The code to create the ingredients for any particular item is generated by their associated macros (e.g., <code>#[salsa::tracked]</code>, <code>#[salsa::input]</code>), but it always follows a particular structure.
To create an ingredient, we first invoke <code>Routes::push</code>, which creates the routes to that ingredient and assigns it an <code>IngredientIndex</code>.
We can then invoke a function such as <code>FunctionIngredient::new</code> to create the structure.