239 lines
7.6 KiB
Rust
239 lines
7.6 KiB
Rust
//!
|
|
#![allow(missing_docs)]
|
|
|
|
use crate::debug::TableEntry;
|
|
use crate::durability::Durability;
|
|
use crate::Cycle;
|
|
use crate::Database;
|
|
use crate::Query;
|
|
use crate::QueryTable;
|
|
use crate::QueryTableMut;
|
|
use std::borrow::Borrow;
|
|
use std::fmt::Debug;
|
|
use std::hash::Hash;
|
|
use triomphe::Arc;
|
|
|
|
pub use crate::derived::DependencyStorage;
|
|
pub use crate::derived::MemoizedStorage;
|
|
pub use crate::input::{InputStorage, UnitInputStorage};
|
|
pub use crate::interned::InternedStorage;
|
|
pub use crate::interned::LookupInternedStorage;
|
|
pub use crate::{revision::Revision, DatabaseKeyIndex, QueryDb, Runtime};
|
|
|
|
/// Defines various associated types. An impl of this
|
|
/// should be generated for your query-context type automatically by
|
|
/// the `database_storage` macro, so you shouldn't need to mess
|
|
/// with this trait directly.
|
|
pub trait DatabaseStorageTypes: Database {
|
|
/// Defines the "storage type", where all the query data is kept.
|
|
/// This type is defined by the `database_storage` macro.
|
|
type DatabaseStorage: Default;
|
|
}
|
|
|
|
/// Internal operations that the runtime uses to operate on the database.
|
|
pub trait DatabaseOps {
|
|
/// Upcast this type to a `dyn Database`.
|
|
fn ops_database(&self) -> &dyn Database;
|
|
|
|
/// Gives access to the underlying salsa runtime.
|
|
fn ops_salsa_runtime(&self) -> &Runtime;
|
|
|
|
/// Gives access to the underlying salsa runtime.
|
|
fn ops_salsa_runtime_mut(&mut self) -> &mut Runtime;
|
|
|
|
/// Formats a database key index in a human readable fashion.
|
|
fn fmt_index(
|
|
&self,
|
|
index: DatabaseKeyIndex,
|
|
fmt: &mut std::fmt::Formatter<'_>,
|
|
) -> std::fmt::Result;
|
|
|
|
/// True if the computed value for `input` may have changed since `revision`.
|
|
fn maybe_changed_after(&self, input: DatabaseKeyIndex, revision: Revision) -> bool;
|
|
|
|
/// Find the `CycleRecoveryStrategy` for a given input.
|
|
fn cycle_recovery_strategy(&self, input: DatabaseKeyIndex) -> CycleRecoveryStrategy;
|
|
|
|
/// Executes the callback for each kind of query.
|
|
fn for_each_query(&self, op: &mut dyn FnMut(&dyn QueryStorageMassOps));
|
|
}
|
|
|
|
/// Internal operations performed on the query storage as a whole
|
|
/// (note that these ops do not need to know the identity of the
|
|
/// query, unlike `QueryStorageOps`).
|
|
pub trait QueryStorageMassOps {
|
|
fn purge(&self);
|
|
}
|
|
|
|
pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
|
|
|
|
pub trait QueryFunction: Query {
|
|
/// See `CycleRecoveryStrategy`
|
|
const CYCLE_STRATEGY: CycleRecoveryStrategy;
|
|
|
|
fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
|
|
|
|
fn cycle_fallback(
|
|
db: &<Self as QueryDb<'_>>::DynDb,
|
|
cycle: &Cycle,
|
|
key: &Self::Key,
|
|
) -> Self::Value {
|
|
let _ = (db, cycle, key);
|
|
panic!("query `{:?}` doesn't support cycle fallback", Self::default())
|
|
}
|
|
}
|
|
|
|
/// Cycle recovery strategy: Is this query capable of recovering from
|
|
/// a cycle that results from executing the function? If so, how?
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum CycleRecoveryStrategy {
|
|
/// Cannot recover from cycles: panic.
|
|
///
|
|
/// This is the default. It is also what happens if a cycle
|
|
/// occurs and the queries involved have different recovery
|
|
/// strategies.
|
|
///
|
|
/// In the case of a failure due to a cycle, the panic
|
|
/// value will be XXX (FIXME).
|
|
Panic,
|
|
|
|
/// Recovers from cycles by storing a sentinel value.
|
|
///
|
|
/// This value is computed by the `QueryFunction::cycle_fallback`
|
|
/// function.
|
|
Fallback,
|
|
}
|
|
|
|
/// Create a query table, which has access to the storage for the query
|
|
/// and offers methods like `get`.
|
|
pub fn get_query_table<'me, Q>(db: &'me <Q as QueryDb<'me>>::DynDb) -> QueryTable<'me, Q>
|
|
where
|
|
Q: Query + 'me,
|
|
Q::Storage: QueryStorageOps<Q>,
|
|
{
|
|
let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
|
|
let query_storage: &Q::Storage = Q::query_storage(group_storage);
|
|
QueryTable::new(db, query_storage)
|
|
}
|
|
|
|
/// Create a mutable query table, which has access to the storage
|
|
/// for the query and offers methods like `set`.
|
|
pub fn get_query_table_mut<'me, Q>(db: &'me mut <Q as QueryDb<'me>>::DynDb) -> QueryTableMut<'me, Q>
|
|
where
|
|
Q: Query,
|
|
{
|
|
let (group_storage, runtime) = HasQueryGroup::group_storage_mut(db);
|
|
let query_storage = Q::query_storage_mut(group_storage);
|
|
QueryTableMut::new(runtime, &**query_storage)
|
|
}
|
|
|
|
pub trait QueryGroup: Sized {
|
|
type GroupStorage;
|
|
|
|
/// Dyn version of the associated database trait.
|
|
type DynDb: ?Sized + Database + HasQueryGroup<Self>;
|
|
}
|
|
|
|
/// Trait implemented by a database for each group that it supports.
|
|
/// `S` and `K` are the types for *group storage* and *group key*, respectively.
|
|
pub trait HasQueryGroup<G>: Database
|
|
where
|
|
G: QueryGroup,
|
|
{
|
|
/// Access the group storage struct from the database.
|
|
fn group_storage(&self) -> &G::GroupStorage;
|
|
|
|
/// Access the group storage struct from the database.
|
|
/// Also returns a ref to the `Runtime`, since otherwise
|
|
/// the database is borrowed and one cannot get access to it.
|
|
fn group_storage_mut(&mut self) -> (&G::GroupStorage, &mut Runtime);
|
|
}
|
|
|
|
// ANCHOR:QueryStorageOps
|
|
pub trait QueryStorageOps<Q>
|
|
where
|
|
Self: QueryStorageMassOps,
|
|
Q: Query,
|
|
{
|
|
// ANCHOR_END:QueryStorageOps
|
|
|
|
/// See CycleRecoveryStrategy
|
|
const CYCLE_STRATEGY: CycleRecoveryStrategy;
|
|
|
|
fn new(group_index: u16) -> Self;
|
|
|
|
/// Format a database key index in a suitable way.
|
|
fn fmt_index(
|
|
&self,
|
|
db: &<Q as QueryDb<'_>>::DynDb,
|
|
index: DatabaseKeyIndex,
|
|
fmt: &mut std::fmt::Formatter<'_>,
|
|
) -> std::fmt::Result;
|
|
|
|
// ANCHOR:maybe_changed_after
|
|
/// True if the value of `input`, which must be from this query, may have
|
|
/// changed after the given revision ended.
|
|
///
|
|
/// This function should only be invoked with a revision less than the current
|
|
/// revision.
|
|
fn maybe_changed_after(
|
|
&self,
|
|
db: &<Q as QueryDb<'_>>::DynDb,
|
|
input: DatabaseKeyIndex,
|
|
revision: Revision,
|
|
) -> bool;
|
|
// ANCHOR_END:maybe_changed_after
|
|
|
|
fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
|
|
Self::CYCLE_STRATEGY
|
|
}
|
|
|
|
// ANCHOR:fetch
|
|
/// Execute the query, returning the result (often, the result
|
|
/// will be memoized). This is the "main method" for
|
|
/// queries.
|
|
///
|
|
/// Returns `Err` in the event of a cycle, meaning that computing
|
|
/// the value for this `key` is recursively attempting to fetch
|
|
/// itself.
|
|
fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value;
|
|
// ANCHOR_END:fetch
|
|
|
|
/// Returns the durability associated with a given key.
|
|
fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability;
|
|
|
|
/// Get the (current) set of the entries in the query storage
|
|
fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
|
|
where
|
|
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
|
|
}
|
|
|
|
/// An optional trait that is implemented for "user mutable" storage:
|
|
/// that is, storage whose value is not derived from other storage but
|
|
/// is set independently.
|
|
pub trait InputQueryStorageOps<Q>
|
|
where
|
|
Q: Query,
|
|
{
|
|
fn set(&self, runtime: &mut Runtime, key: &Q::Key, new_value: Q::Value, durability: Durability);
|
|
}
|
|
|
|
/// An optional trait that is implemented for "user mutable" storage:
|
|
/// that is, storage whose value is not derived from other storage but
|
|
/// is set independently.
|
|
pub trait LruQueryStorageOps {
|
|
fn set_lru_capacity(&self, new_capacity: usize);
|
|
}
|
|
|
|
pub trait DerivedQueryStorageOps<Q>
|
|
where
|
|
Q: Query,
|
|
{
|
|
fn invalidate<S>(&self, runtime: &mut Runtime, key: &S)
|
|
where
|
|
S: Eq + Hash,
|
|
Q::Key: Borrow<S>;
|
|
}
|
|
|
|
pub type CycleParticipants = Arc<Vec<DatabaseKeyIndex>>;
|