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