#[tracked]Expand description
Defines a tracked struct or function, or enables tracked methods in an impl block.
The accepted syntax and generated API depend on the annotated item. See the sections below for the options and field attributes accepted by each form.
§Tracked structs
A tracked struct represents a derived entity created during tracked-function execution. Its identity belongs to the producing query, which can recreate and update the entity in a later revision.
The annotated item must have named fields and exactly one lifetime parameter, conventionally
'db; type and const parameters are not supported. A field whose type is unconditionally
'static is accepted directly; any other field must implement salsa::SalsaValue.
See tracked structs in the salsa crate documentation for their identity, change tracking,
and lifecycle.
§Struct options
constructor = IDENTrenames the generated constructor fromnewtoIDENT.debugimplementsDebugusing the field values when a database is attached to the current thread. The generateddefault_debug_fmtmethod can also be called from a manualDebugimplementation.heap_size = PATHrecords heap use for Salsa’s unstable memory-usage reporting.PATHmust accept a reference to the tuple of all fields and return its heap allocation size in bytes.persistenables persistent caching when Salsa’spersistencefeature is enabled. Fields are serialized as a tuple withserdeby default.persist(serialize = PATH, deserialize = PATH)enables persistence with custom tuple serialization functions. Either path may be omitted to use the correspondingserdeimplementation.
§Struct field attributes
#[tracked]excludes the field from the struct’s identity. When the producing query recreates the same entity with a new value for this field, Salsa updates the existing entity instead of creating a new one. Reads of the field are tracked separately, so changing it invalidates only queries that read that field. Use this for properties that may change while the conceptual entity remains the same.#[returns(MODE)]selects how the getter returns the field.ref(the default) returns&FieldTy;clonereturns an ownedFieldTyusing [Clone];copyreturns an ownedFieldTyusing [Copy]; andderefusesDerefto return&<FieldTy as Deref>::Target.as_refandas_derefusesalsa::SalsaAsRefandsalsa::SalsaAsDerefto return borrowed forms such asOption<&T>andOption<&T::Target>. Every borrowed result is tied to the database borrow.#[get(IDENT)]renames the generated getter.#[no_eq]replaces the stored value and treats the field as changed whenever the struct is recreated, avoiding the [PartialEq] requirement. It is most useful together with#[tracked]: because the field does not contribute to identity, the struct can retain its identity when recreated, while readers of the field are always invalidated.- Unsafe:
#[salsa_value(unsafe(prove_safe_to_retain_manually))]suppresses the retention check for this field. The caller must ensure Salsa can retain the field and expose it with a later database lifetime.
Other attributes, including documentation and lint attributes, are copied to the generated getter.
§Tracked functions
A tracked function memoizes its result and records the Salsa values read by its body. Salsa reuses the memoized result while those dependencies remain unchanged.
The first parameter must be an immutable &dyn DatabaseTrait; the remaining parameters form
the query key. The function may declare one database lifetime but no type or const parameters.
Every key parameter and the output must implement [Send] + [Sync]. With no key parameters,
the function has one memoized query per database. A single key parameter must be a Salsa struct
and uses its ID directly. With multiple key parameters, Salsa first interns their tuple to
obtain an ID, adding an interning step to every call. Each key parameter must additionally
implement [Clone] + Eq + Hash. Equality and hashing determine whether calls use the
same memo, and Salsa always clones the stored tuple when materializing the function arguments.
Interned key parameters and outputs whose types are not unconditionally 'static must implement
salsa::SalsaValue.
See tracked functions in the salsa crate documentation for query identity, dependency
tracking, result equality, and memo lifecycle.
§Function options
returns(MODE)selects how callers receive the memoized result.ref(the default) returns&Output;clonereturns an ownedOutputusing [Clone];copyreturns an ownedOutputusing [Copy]; andderefusesDerefto return&<Output as Deref>::Target.as_refandas_derefusesalsa::SalsaAsRefandsalsa::SalsaAsDerefto return borrowed forms such asOption<&T>andOption<&T::Target>. Every borrowed result is tied to the database borrow and remains stored in the query’s memo.no_eqtreats every newly computed result as changed and removes the output’s equality requirement. It cannot be combined withcycle_fn.specifygeneratesFUNCTION::specify(db, key, value). It supports queries that have both a per-key incremental implementation and a batch implementation that computes many results at once. The function must take exactly one key argument, and it must be a tracked struct, not an input or interned struct.specifymust be called during the same tracked query invocation that created the key. It cannot be combined withlru. See specifying query results in the Salsa book for an example.lru = INTEGERbounds the number of memoized values retained by the function and sets the initial capacity used byFUNCTION::set_lru_capacity.cycle_initial = EXPRenables fixed-point cycle recovery and computes the initial value. The expression is called as(db, cycle_head_id, query_arguments...).cycle_fn = EXPRcombines successive fixed-point values. It must be accompanied bycycle_initialand is called as(db, cycle, previous_value, new_value, query_arguments...). See fixed-point cycle recovery in the Salsa book for the convergence requirements and a complete example.cycle_result = EXPRsupplies an immediate fallback for cycles instead of fixed-point iteration. It is called with the same arguments ascycle_initialand cannot be combined withcycle_initialorcycle_fn.heap_size = PATHrecords heap use for Salsa’s unstable memory-usage reporting.PATHmust accept a reference to the output and return its heap allocation size in bytes.persistenables persistent caching when Salsa’spersistencefeature is enabled. The query inputs and output must implementserde::Serializeandserde::Deserialize.self_ty = TYPEprefixes the query’s debug name withTYPE. The impl-block form supplies this automatically for methods and associated functions.
§Legacy function adapter
- Unsafe:
unsafe(non_salsa_values)is strongly discouraged. It adapts output or internally interned input types that do not implementsalsa::SalsaValueby suppressing the generated checks. The caller becomes responsible for ensuring retained values remain valid across revisions. Prefer deriving or implementingsalsa::SalsaValuefor those types.
§Tracked impl blocks
Applying #[salsa::tracked] to an inherent or trait impl allows individual methods and
associated functions in it to also use #[salsa::tracked(...)]. The outer attribute accepts no
options; inner attributes accept all tracked-function options.
A tracked method takes self by value followed by the database parameter. A tracked associated
function takes the database parameter first. Other methods and associated items are left
unchanged.
§Examples
#[salsa::input]
struct File {
#[returns(deref)]
text: String,
}
#[salsa::tracked(returns(copy))]
fn word_count(db: &dyn salsa::Database, file: File) -> usize {
file.text(db).split_whitespace().count()
}
#[salsa::tracked]
impl File {
#[salsa::tracked(returns(copy))]
fn line_count(self, db: &dyn salsa::Database) -> usize {
self.text(db).lines().count()
}
}