mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-23 13:10:19 +00:00
Merge pull request #51 from matklad/plumbing
Hide public impl detail in the plumbing module
This commit is contained in:
commit
6a61233902
5 changed files with 161 additions and 141 deletions
|
@ -1,9 +1,9 @@
|
||||||
//! Debugging APIs: these are meant for use when unit-testing or
|
//! Debugging APIs: these are meant for use when unit-testing or
|
||||||
//! debugging your application but aren't ordinarily needed.
|
//! debugging your application but aren't ordinarily needed.
|
||||||
|
|
||||||
|
use crate::plumbing::QueryStorageOps;
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
use crate::Query;
|
use crate::Query;
|
||||||
use crate::QueryStorageOps;
|
|
||||||
use crate::QueryTable;
|
use crate::QueryTable;
|
||||||
|
|
||||||
pub trait DebugQueryTable {
|
pub trait DebugQueryTable {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
use crate::plumbing::CycleDetected;
|
||||||
|
use crate::plumbing::QueryDescriptor;
|
||||||
|
use crate::plumbing::QueryFunction;
|
||||||
|
use crate::plumbing::QueryStorageOps;
|
||||||
|
use crate::plumbing::UncheckedMutQueryStorageOps;
|
||||||
use crate::runtime::ChangedAt;
|
use crate::runtime::ChangedAt;
|
||||||
use crate::runtime::QueryDescriptorSet;
|
use crate::runtime::QueryDescriptorSet;
|
||||||
use crate::runtime::Revision;
|
use crate::runtime::Revision;
|
||||||
use crate::runtime::Runtime;
|
use crate::runtime::Runtime;
|
||||||
use crate::runtime::RuntimeId;
|
use crate::runtime::RuntimeId;
|
||||||
use crate::runtime::StampedValue;
|
use crate::runtime::StampedValue;
|
||||||
use crate::CycleDetected;
|
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
use crate::QueryDescriptor;
|
|
||||||
use crate::QueryFunction;
|
|
||||||
use crate::QueryStorageOps;
|
|
||||||
use crate::UncheckedMutQueryStorageOps;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
use crate::plumbing::CycleDetected;
|
||||||
|
use crate::plumbing::InputQueryStorageOps;
|
||||||
|
use crate::plumbing::QueryStorageOps;
|
||||||
|
use crate::plumbing::UncheckedMutQueryStorageOps;
|
||||||
use crate::runtime::ChangedAt;
|
use crate::runtime::ChangedAt;
|
||||||
use crate::runtime::Revision;
|
use crate::runtime::Revision;
|
||||||
use crate::runtime::StampedValue;
|
use crate::runtime::StampedValue;
|
||||||
use crate::CycleDetected;
|
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
use crate::InputQueryStorageOps;
|
|
||||||
use crate::Query;
|
use crate::Query;
|
||||||
use crate::QueryStorageOps;
|
|
||||||
use crate::UncheckedMutQueryStorageOps;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
164
src/lib.rs
164
src/lib.rs
|
@ -1,21 +1,30 @@
|
||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
mod derived;
|
||||||
|
mod input;
|
||||||
|
mod runtime;
|
||||||
|
|
||||||
|
pub mod debug;
|
||||||
|
/// Items in this module are public for implementation reasons,
|
||||||
|
/// and are exempt from the SemVer guarantees.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub mod plumbing;
|
||||||
|
|
||||||
|
use crate::plumbing::CycleDetected;
|
||||||
|
use crate::plumbing::InputQueryStorageOps;
|
||||||
|
use crate::plumbing::QueryStorageOps;
|
||||||
|
use crate::plumbing::UncheckedMutQueryStorageOps;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
pub mod debug;
|
|
||||||
pub mod derived;
|
|
||||||
pub mod input;
|
|
||||||
pub mod runtime;
|
|
||||||
|
|
||||||
pub use crate::runtime::Runtime;
|
pub use crate::runtime::Runtime;
|
||||||
|
|
||||||
/// The base trait which your "query context" must implement. Gives
|
/// The base trait which your "query context" must implement. Gives
|
||||||
/// access to the salsa runtime, which you must embed into your query
|
/// access to the salsa runtime, which you must embed into your query
|
||||||
/// context (along with whatever other state you may require).
|
/// context (along with whatever other state you may require).
|
||||||
pub trait Database: DatabaseStorageTypes {
|
pub trait Database: plumbing::DatabaseStorageTypes {
|
||||||
/// Gives access to the underlying salsa runtime.
|
/// Gives access to the underlying salsa runtime.
|
||||||
fn salsa_runtime(&self) -> &Runtime<Self>;
|
fn salsa_runtime(&self) -> &Runtime<Self>;
|
||||||
|
|
||||||
|
@ -25,9 +34,9 @@ pub trait Database: DatabaseStorageTypes {
|
||||||
fn query<Q>(&self, query: Q) -> QueryTable<'_, Self, Q>
|
fn query<Q>(&self, query: Q) -> QueryTable<'_, Self, Q>
|
||||||
where
|
where
|
||||||
Q: Query<Self>,
|
Q: Query<Self>,
|
||||||
Self: GetQueryTable<Q>,
|
Self: plumbing::GetQueryTable<Q>,
|
||||||
{
|
{
|
||||||
<Self as GetQueryTable<Q>>::get_query_table(self)
|
<Self as plumbing::GetQueryTable<Q>>::get_query_table(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,115 +54,10 @@ pub trait ParallelDatabase: Database + Send {
|
||||||
fn fork(&self) -> Self;
|
fn fork(&self) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines the `QueryDescriptor` associated type. 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: Sized {
|
|
||||||
/// A "query descriptor" packages up all the possible queries and a key.
|
|
||||||
/// It is used to store information about (e.g.) the stack.
|
|
||||||
///
|
|
||||||
/// At runtime, it can be implemented in various ways: a monster enum
|
|
||||||
/// works for a fixed set of queries, but a boxed trait object is good
|
|
||||||
/// for a more open-ended option.
|
|
||||||
type QueryDescriptor: QueryDescriptor<Self>;
|
|
||||||
|
|
||||||
/// Defines the "storage type", where all the query data is kept.
|
|
||||||
/// This type is defined by the `database_storage` macro.
|
|
||||||
type DatabaseStorage: Default;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait QueryDescriptor<DB>: Clone + Debug + Eq + Hash + Send + Sync {
|
|
||||||
/// Returns true if the value of this query may have changed since
|
|
||||||
/// the given revision.
|
|
||||||
fn maybe_changed_since(&self, db: &DB, revision: runtime::Revision) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait QueryFunction<DB: Database>: Query<DB> {
|
|
||||||
fn execute(db: &DB, key: Self::Key) -> Self::Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
||||||
type Key: Clone + Debug + Hash + Eq;
|
type Key: Clone + Debug + Hash + Eq;
|
||||||
type Value: Clone + Debug + Hash + Eq;
|
type Value: Clone + Debug + Hash + Eq;
|
||||||
type Storage: QueryStorageOps<DB, Self> + Send + Sync;
|
type Storage: plumbing::QueryStorageOps<DB, Self> + Send + Sync;
|
||||||
}
|
|
||||||
|
|
||||||
pub trait GetQueryTable<Q: Query<Self>>: Database {
|
|
||||||
fn get_query_table(db: &Self) -> QueryTable<'_, Self, Q>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait QueryStorageOps<DB, Q>: Default
|
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
Q: Query<DB>,
|
|
||||||
{
|
|
||||||
/// 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 try_fetch(
|
|
||||||
&self,
|
|
||||||
db: &DB,
|
|
||||||
key: &Q::Key,
|
|
||||||
descriptor: &DB::QueryDescriptor,
|
|
||||||
) -> Result<Q::Value, CycleDetected>;
|
|
||||||
|
|
||||||
/// True if the query **may** have changed since the given
|
|
||||||
/// revision. The query will answer this question with as much
|
|
||||||
/// precision as it is able to do based on its storage type. In
|
|
||||||
/// the event of a cycle being detected as part of this function,
|
|
||||||
/// it returns true.
|
|
||||||
///
|
|
||||||
/// Example: The steps for a memoized query are as follows.
|
|
||||||
///
|
|
||||||
/// - If the query has already been computed:
|
|
||||||
/// - Check the inputs that the previous computation used
|
|
||||||
/// recursively to see if *they* have changed. If they have
|
|
||||||
/// not, then return false.
|
|
||||||
/// - If they have, then the query is re-executed and the new
|
|
||||||
/// result is compared against the old result. If it is equal,
|
|
||||||
/// then return false.
|
|
||||||
/// - Return true.
|
|
||||||
///
|
|
||||||
/// Other storage types will skip some or all of these steps.
|
|
||||||
fn maybe_changed_since(
|
|
||||||
&self,
|
|
||||||
db: &DB,
|
|
||||||
revision: runtime::Revision,
|
|
||||||
key: &Q::Key,
|
|
||||||
descriptor: &DB::QueryDescriptor,
|
|
||||||
) -> bool;
|
|
||||||
|
|
||||||
/// Check if `key` is (currently) believed to be a constant.
|
|
||||||
fn is_constant(&self, db: &DB, key: &Q::Key) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<DB, Q>: Default
|
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
Q: Query<DB>,
|
|
||||||
{
|
|
||||||
fn set(&self, db: &DB, key: &Q::Key, new_value: Q::Value);
|
|
||||||
|
|
||||||
fn set_constant(&self, db: &DB, key: &Q::Key, new_value: 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 UncheckedMutQueryStorageOps<DB, Q>: Default
|
|
||||||
where
|
|
||||||
DB: Database,
|
|
||||||
Q: Query<DB>,
|
|
||||||
{
|
|
||||||
fn set_unchecked(&self, db: &DB, key: &Q::Key, new_value: Q::Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
|
@ -167,8 +71,6 @@ where
|
||||||
descriptor_fn: fn(&DB, &Q::Key) -> DB::QueryDescriptor,
|
descriptor_fn: fn(&DB, &Q::Key) -> DB::QueryDescriptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CycleDetected;
|
|
||||||
|
|
||||||
impl<DB, Q> QueryTable<'_, DB, Q>
|
impl<DB, Q> QueryTable<'_, DB, Q>
|
||||||
where
|
where
|
||||||
DB: Database,
|
DB: Database,
|
||||||
|
@ -187,7 +89,7 @@ where
|
||||||
/// an active query computation.
|
/// an active query computation.
|
||||||
pub fn set(&self, key: Q::Key, value: Q::Value)
|
pub fn set(&self, key: Q::Key, value: Q::Value)
|
||||||
where
|
where
|
||||||
Q::Storage: InputQueryStorageOps<DB, Q>,
|
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||||
{
|
{
|
||||||
self.storage.set(self.db, &key, value);
|
self.storage.set(self.db, &key, value);
|
||||||
}
|
}
|
||||||
|
@ -197,7 +99,7 @@ where
|
||||||
/// outside of an active query computation.
|
/// outside of an active query computation.
|
||||||
pub fn set_constant(&self, key: Q::Key, value: Q::Value)
|
pub fn set_constant(&self, key: Q::Key, value: Q::Value)
|
||||||
where
|
where
|
||||||
Q::Storage: InputQueryStorageOps<DB, Q>,
|
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||||
{
|
{
|
||||||
self.storage.set_constant(self.db, &key, value);
|
self.storage.set_constant(self.db, &key, value);
|
||||||
}
|
}
|
||||||
|
@ -219,7 +121,7 @@ where
|
||||||
/// and thus control what it sees when it executes.
|
/// and thus control what it sees when it executes.
|
||||||
pub fn set_unchecked(&self, key: Q::Key, value: Q::Value)
|
pub fn set_unchecked(&self, key: Q::Key, value: Q::Value)
|
||||||
where
|
where
|
||||||
Q::Storage: UncheckedMutQueryStorageOps<DB, Q>,
|
Q::Storage: plumbing::UncheckedMutQueryStorageOps<DB, Q>,
|
||||||
{
|
{
|
||||||
self.storage.set_unchecked(self.db, &key, value);
|
self.storage.set_unchecked(self.db, &key, value);
|
||||||
}
|
}
|
||||||
|
@ -296,11 +198,11 @@ macro_rules! query_group {
|
||||||
)*
|
)*
|
||||||
}];
|
}];
|
||||||
) => {
|
) => {
|
||||||
$($trait_attr)* $v trait $query_trait: $($crate::GetQueryTable<$QueryType> +)* $($header)* {
|
$($trait_attr)* $v trait $query_trait: $($crate::plumbing::GetQueryTable<$QueryType> +)* $($header)* {
|
||||||
$(
|
$(
|
||||||
$(#[$method_attr])*
|
$(#[$method_attr])*
|
||||||
fn $method_name(&self, key: $key_ty) -> $value_ty {
|
fn $method_name(&self, key: $key_ty) -> $value_ty {
|
||||||
<Self as $crate::GetQueryTable<$QueryType>>::get_query_table(self)
|
<Self as $crate::plumbing::GetQueryTable<$QueryType>>::get_query_table(self)
|
||||||
.get(key)
|
.get(key)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -384,7 +286,7 @@ macro_rules! query_group {
|
||||||
query_type($QueryType:ty);
|
query_type($QueryType:ty);
|
||||||
]
|
]
|
||||||
) => {
|
) => {
|
||||||
impl<DB> $crate::QueryFunction<DB> for $QueryType
|
impl<DB> $crate::plumbing::QueryFunction<DB> for $QueryType
|
||||||
where DB: $DbTrait
|
where DB: $DbTrait
|
||||||
{
|
{
|
||||||
fn execute(db: &DB, key: <Self as $crate::Query<DB>>::Key)
|
fn execute(db: &DB, key: <Self as $crate::Query<DB>>::Key)
|
||||||
|
@ -420,25 +322,25 @@ macro_rules! query_group {
|
||||||
(
|
(
|
||||||
@storage_ty[$DB:ident, $Self:ident, memoized]
|
@storage_ty[$DB:ident, $Self:ident, memoized]
|
||||||
) => {
|
) => {
|
||||||
$crate::derived::MemoizedStorage<$DB, $Self>
|
$crate::plumbing::MemoizedStorage<$DB, $Self>
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
@storage_ty[$DB:ident, $Self:ident, volatile]
|
@storage_ty[$DB:ident, $Self:ident, volatile]
|
||||||
) => {
|
) => {
|
||||||
$crate::derived::VolatileStorage<$DB, $Self>
|
$crate::plumbing::VolatileStorage<$DB, $Self>
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
@storage_ty[$DB:ident, $Self:ident, dependencies]
|
@storage_ty[$DB:ident, $Self:ident, dependencies]
|
||||||
) => {
|
) => {
|
||||||
$crate::derived::DependencyStorage<$DB, $Self>
|
$crate::plumbing::DependencyStorage<$DB, $Self>
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
@storage_ty[$DB:ident, $Self:ident, input]
|
@storage_ty[$DB:ident, $Self:ident, input]
|
||||||
) => {
|
) => {
|
||||||
$crate::input::InputStorage<DB, Self>
|
$crate::plumbing::InputStorage<DB, Self>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,16 +390,16 @@ macro_rules! database_storage {
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::DatabaseStorageTypes for $Database {
|
impl $crate::plumbing::DatabaseStorageTypes for $Database {
|
||||||
type QueryDescriptor = __SalsaQueryDescriptor;
|
type QueryDescriptor = __SalsaQueryDescriptor;
|
||||||
type DatabaseStorage = $Storage;
|
type DatabaseStorage = $Storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::QueryDescriptor<$Database> for __SalsaQueryDescriptor {
|
impl $crate::plumbing::QueryDescriptor<$Database> for __SalsaQueryDescriptor {
|
||||||
fn maybe_changed_since(
|
fn maybe_changed_since(
|
||||||
&self,
|
&self,
|
||||||
db: &$Database,
|
db: &$Database,
|
||||||
revision: $crate::runtime::Revision,
|
revision: $crate::plumbing::Revision,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
$(
|
$(
|
||||||
|
@ -505,7 +407,7 @@ macro_rules! database_storage {
|
||||||
__SalsaQueryDescriptorKind::$query_method(key) => {
|
__SalsaQueryDescriptorKind::$query_method(key) => {
|
||||||
let runtime = $crate::Database::salsa_runtime(db);
|
let runtime = $crate::Database::salsa_runtime(db);
|
||||||
let storage = &runtime.storage().$query_method;
|
let storage = &runtime.storage().$query_method;
|
||||||
<_ as $crate::QueryStorageOps<$Database, $QueryType>>::maybe_changed_since(
|
<_ as $crate::plumbing::QueryStorageOps<$Database, $QueryType>>::maybe_changed_since(
|
||||||
storage,
|
storage,
|
||||||
db,
|
db,
|
||||||
revision,
|
revision,
|
||||||
|
@ -523,7 +425,7 @@ macro_rules! database_storage {
|
||||||
impl $TraitName for $Database { }
|
impl $TraitName for $Database { }
|
||||||
|
|
||||||
$(
|
$(
|
||||||
impl $crate::GetQueryTable<$QueryType> for $Database {
|
impl $crate::plumbing::GetQueryTable<$QueryType> for $Database {
|
||||||
fn get_query_table(
|
fn get_query_table(
|
||||||
db: &Self,
|
db: &Self,
|
||||||
) -> $crate::QueryTable<'_, Self, $QueryType> {
|
) -> $crate::QueryTable<'_, Self, $QueryType> {
|
||||||
|
|
118
src/plumbing.rs
Normal file
118
src/plumbing.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
use crate::Database;
|
||||||
|
use crate::Query;
|
||||||
|
use crate::QueryTable;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub use crate::derived::DependencyStorage;
|
||||||
|
pub use crate::derived::MemoizedStorage;
|
||||||
|
pub use crate::derived::VolatileStorage;
|
||||||
|
pub use crate::input::InputStorage;
|
||||||
|
pub use crate::runtime::Revision;
|
||||||
|
|
||||||
|
pub struct CycleDetected;
|
||||||
|
|
||||||
|
/// Defines the `QueryDescriptor` associated type. 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: Sized {
|
||||||
|
/// A "query descriptor" packages up all the possible queries and a key.
|
||||||
|
/// It is used to store information about (e.g.) the stack.
|
||||||
|
///
|
||||||
|
/// At runtime, it can be implemented in various ways: a monster enum
|
||||||
|
/// works for a fixed set of queries, but a boxed trait object is good
|
||||||
|
/// for a more open-ended option.
|
||||||
|
type QueryDescriptor: QueryDescriptor<Self>;
|
||||||
|
|
||||||
|
/// Defines the "storage type", where all the query data is kept.
|
||||||
|
/// This type is defined by the `database_storage` macro.
|
||||||
|
type DatabaseStorage: Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait QueryDescriptor<DB>: Clone + Debug + Eq + Hash + Send + Sync {
|
||||||
|
/// Returns true if the value of this query may have changed since
|
||||||
|
/// the given revision.
|
||||||
|
fn maybe_changed_since(&self, db: &DB, revision: Revision) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait QueryFunction<DB: Database>: Query<DB> {
|
||||||
|
fn execute(db: &DB, key: Self::Key) -> Self::Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetQueryTable<Q: Query<Self>>: Database {
|
||||||
|
fn get_query_table(db: &Self) -> QueryTable<'_, Self, Q>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait QueryStorageOps<DB, Q>: Default
|
||||||
|
where
|
||||||
|
DB: Database,
|
||||||
|
Q: Query<DB>,
|
||||||
|
{
|
||||||
|
/// 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 try_fetch(
|
||||||
|
&self,
|
||||||
|
db: &DB,
|
||||||
|
key: &Q::Key,
|
||||||
|
descriptor: &DB::QueryDescriptor,
|
||||||
|
) -> Result<Q::Value, CycleDetected>;
|
||||||
|
|
||||||
|
/// True if the query **may** have changed since the given
|
||||||
|
/// revision. The query will answer this question with as much
|
||||||
|
/// precision as it is able to do based on its storage type. In
|
||||||
|
/// the event of a cycle being detected as part of this function,
|
||||||
|
/// it returns true.
|
||||||
|
///
|
||||||
|
/// Example: The steps for a memoized query are as follows.
|
||||||
|
///
|
||||||
|
/// - If the query has already been computed:
|
||||||
|
/// - Check the inputs that the previous computation used
|
||||||
|
/// recursively to see if *they* have changed. If they have
|
||||||
|
/// not, then return false.
|
||||||
|
/// - If they have, then the query is re-executed and the new
|
||||||
|
/// result is compared against the old result. If it is equal,
|
||||||
|
/// then return false.
|
||||||
|
/// - Return true.
|
||||||
|
///
|
||||||
|
/// Other storage types will skip some or all of these steps.
|
||||||
|
fn maybe_changed_since(
|
||||||
|
&self,
|
||||||
|
db: &DB,
|
||||||
|
revision: Revision,
|
||||||
|
key: &Q::Key,
|
||||||
|
descriptor: &DB::QueryDescriptor,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
|
/// Check if `key` is (currently) believed to be a constant.
|
||||||
|
fn is_constant(&self, db: &DB, key: &Q::Key) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<DB, Q>: Default
|
||||||
|
where
|
||||||
|
DB: Database,
|
||||||
|
Q: Query<DB>,
|
||||||
|
{
|
||||||
|
fn set(&self, db: &DB, key: &Q::Key, new_value: Q::Value);
|
||||||
|
|
||||||
|
fn set_constant(&self, db: &DB, key: &Q::Key, new_value: 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 UncheckedMutQueryStorageOps<DB, Q>: Default
|
||||||
|
where
|
||||||
|
DB: Database,
|
||||||
|
Q: Query<DB>,
|
||||||
|
{
|
||||||
|
fn set_unchecked(&self, db: &DB, key: &Q::Key, new_value: Q::Value);
|
||||||
|
}
|
Loading…
Reference in a new issue