salsa/
plumbing.rs

1#![allow(missing_docs)]
2
3use crate::debug::TableEntry;
4use crate::durability::Durability;
5use crate::Cycle;
6use crate::Database;
7use crate::Query;
8use crate::QueryTable;
9use crate::QueryTableMut;
10use std::borrow::Borrow;
11use std::fmt::Debug;
12use std::hash::Hash;
13use triomphe::Arc;
14
15pub use crate::derived::DependencyStorage;
16pub use crate::derived::MemoizedStorage;
17pub use crate::input::InputStorage;
18pub use crate::interned::InternedStorage;
19pub use crate::interned::LookupInternedStorage;
20pub use crate::{revision::Revision, DatabaseKeyIndex, QueryDb, Runtime};
21
22/// Defines various associated types. An impl of this
23/// should be generated for your query-context type automatically by
24/// the `database_storage` macro, so you shouldn't need to mess
25/// with this trait directly.
26pub trait DatabaseStorageTypes: Database {
27    /// Defines the "storage type", where all the query data is kept.
28    /// This type is defined by the `database_storage` macro.
29    type DatabaseStorage: Default;
30}
31
32/// Internal operations that the runtime uses to operate on the database.
33pub trait DatabaseOps {
34    /// Upcast this type to a `dyn Database`.
35    fn ops_database(&self) -> &dyn Database;
36
37    /// Gives access to the underlying salsa runtime.
38    fn ops_salsa_runtime(&self) -> &Runtime;
39
40    /// Gives access to the underlying salsa runtime.
41    fn ops_salsa_runtime_mut(&mut self) -> &mut Runtime;
42
43    /// Formats a database key index in a human readable fashion.
44    fn fmt_index(
45        &self,
46        index: DatabaseKeyIndex,
47        fmt: &mut std::fmt::Formatter<'_>,
48    ) -> std::fmt::Result;
49
50    /// True if the computed value for `input` may have changed since `revision`.
51    fn maybe_changed_after(&self, input: DatabaseKeyIndex, revision: Revision) -> bool;
52
53    /// Find the `CycleRecoveryStrategy` for a given input.
54    fn cycle_recovery_strategy(&self, input: DatabaseKeyIndex) -> CycleRecoveryStrategy;
55
56    /// Executes the callback for each kind of query.
57    fn for_each_query(&self, op: &mut dyn FnMut(&dyn QueryStorageMassOps));
58}
59
60/// Internal operations performed on the query storage as a whole
61/// (note that these ops do not need to know the identity of the
62/// query, unlike `QueryStorageOps`).
63pub trait QueryStorageMassOps {
64    fn purge(&self);
65}
66
67pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
68
69pub trait QueryFunction: Query {
70    /// See `CycleRecoveryStrategy`
71    const CYCLE_STRATEGY: CycleRecoveryStrategy;
72
73    fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
74
75    fn cycle_fallback(
76        db: &<Self as QueryDb<'_>>::DynDb,
77        cycle: &Cycle,
78        key: &Self::Key,
79    ) -> Self::Value {
80        let _ = (db, cycle, key);
81        panic!(
82            "query `{:?}` doesn't support cycle fallback",
83            Self::default()
84        )
85    }
86}
87
88/// Cycle recovery strategy: Is this query capable of recovering from
89/// a cycle that results from executing the function? If so, how?
90#[derive(Copy, Clone, Debug, PartialEq, Eq)]
91pub enum CycleRecoveryStrategy {
92    /// Cannot recover from cycles: panic.
93    ///
94    /// This is the default. It is also what happens if a cycle
95    /// occurs and the queries involved have different recovery
96    /// strategies.
97    ///
98    /// In the case of a failure due to a cycle, the panic
99    /// value will be XXX (FIXME).
100    Panic,
101
102    /// Recovers from cycles by storing a sentinel value.
103    ///
104    /// This value is computed by the `QueryFunction::cycle_fallback`
105    /// function.
106    Fallback,
107}
108
109/// Create a query table, which has access to the storage for the query
110/// and offers methods like `get`.
111pub fn get_query_table<'me, Q>(db: &'me <Q as QueryDb<'me>>::DynDb) -> QueryTable<'me, Q>
112where
113    Q: Query + 'me,
114    Q::Storage: QueryStorageOps<Q>,
115{
116    let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
117    let query_storage: &Q::Storage = Q::query_storage(group_storage);
118    QueryTable::new(db, query_storage)
119}
120
121/// Create a mutable query table, which has access to the storage
122/// for the query and offers methods like `set`.
123pub fn get_query_table_mut<'me, Q>(db: &'me mut <Q as QueryDb<'me>>::DynDb) -> QueryTableMut<'me, Q>
124where
125    Q: Query,
126{
127    let (group_storage, runtime) = HasQueryGroup::group_storage_mut(db);
128    let query_storage = Q::query_storage_mut(group_storage);
129    QueryTableMut::new(runtime, &**query_storage)
130}
131
132pub trait QueryGroup: Sized {
133    type GroupStorage;
134
135    /// Dyn version of the associated database trait.
136    type DynDb: ?Sized + Database + HasQueryGroup<Self>;
137}
138
139/// Trait implemented by a database for each group that it supports.
140/// `S` and `K` are the types for *group storage* and *group key*, respectively.
141pub trait HasQueryGroup<G>: Database
142where
143    G: QueryGroup,
144{
145    /// Access the group storage struct from the database.
146    fn group_storage(&self) -> &G::GroupStorage;
147
148    /// Access the group storage struct from the database.
149    /// Also returns a ref to the `Runtime`, since otherwise
150    /// the database is borrowed and one cannot get access to it.
151    fn group_storage_mut(&mut self) -> (&G::GroupStorage, &mut Runtime);
152}
153
154// ANCHOR:QueryStorageOps
155pub trait QueryStorageOps<Q>
156where
157    Self: QueryStorageMassOps,
158    Q: Query,
159{
160    // ANCHOR_END:QueryStorageOps
161
162    /// See CycleRecoveryStrategy
163    const CYCLE_STRATEGY: CycleRecoveryStrategy;
164
165    fn new(group_index: u16) -> Self;
166
167    /// Format a database key index in a suitable way.
168    fn fmt_index(
169        &self,
170        db: &<Q as QueryDb<'_>>::DynDb,
171        index: DatabaseKeyIndex,
172        fmt: &mut std::fmt::Formatter<'_>,
173    ) -> std::fmt::Result;
174
175    // ANCHOR:maybe_changed_after
176    /// True if the value of `input`, which must be from this query, may have
177    /// changed after the given revision ended.
178    ///
179    /// This function should only be invoked with a revision less than the current
180    /// revision.
181    fn maybe_changed_after(
182        &self,
183        db: &<Q as QueryDb<'_>>::DynDb,
184        input: DatabaseKeyIndex,
185        revision: Revision,
186    ) -> bool;
187    // ANCHOR_END:maybe_changed_after
188
189    fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
190        Self::CYCLE_STRATEGY
191    }
192
193    // ANCHOR:fetch
194    /// Execute the query, returning the result (often, the result
195    /// will be memoized).  This is the "main method" for
196    /// queries.
197    ///
198    /// Returns `Err` in the event of a cycle, meaning that computing
199    /// the value for this `key` is recursively attempting to fetch
200    /// itself.
201    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value;
202    // ANCHOR_END:fetch
203
204    /// Returns the durability associated with a given key.
205    fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability;
206
207    /// Get the (current) set of the entries in the query storage
208    fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
209    where
210        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
211}
212
213/// An optional trait that is implemented for "user mutable" storage:
214/// that is, storage whose value is not derived from other storage but
215/// is set independently.
216pub trait InputQueryStorageOps<Q>
217where
218    Q: Query,
219{
220    fn set(&self, runtime: &mut Runtime, key: &Q::Key, new_value: Q::Value, durability: Durability);
221}
222
223/// An optional trait that is implemented for "user mutable" storage:
224/// that is, storage whose value is not derived from other storage but
225/// is set independently.
226pub trait LruQueryStorageOps {
227    fn set_lru_capacity(&self, new_capacity: usize);
228}
229
230pub trait DerivedQueryStorageOps<Q>
231where
232    Q: Query,
233{
234    fn invalidate<S>(&self, runtime: &mut Runtime, key: &S)
235    where
236        S: Eq + Hash,
237        Q::Key: Borrow<S>;
238}
239
240pub type CycleParticipants = Arc<Vec<DatabaseKeyIndex>>;