From 4401e88fbae210c71674d9545b879db3b8325e08 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 16 Oct 2018 11:20:49 +0300 Subject: [PATCH] Hide public impl detail in the plumbing module --- src/debug.rs | 2 +- src/derived.rs | 10 +-- src/input.rs | 8 +-- src/lib.rs | 164 ++++++++++-------------------------------------- src/plumbing.rs | 118 ++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+), 141 deletions(-) create mode 100644 src/plumbing.rs diff --git a/src/debug.rs b/src/debug.rs index 491ffdf..626c224 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,9 +1,9 @@ //! Debugging APIs: these are meant for use when unit-testing or //! debugging your application but aren't ordinarily needed. +use crate::plumbing::QueryStorageOps; use crate::Database; use crate::Query; -use crate::QueryStorageOps; use crate::QueryTable; pub trait DebugQueryTable { diff --git a/src/derived.rs b/src/derived.rs index 8d4b92a..271bbe5 100644 --- a/src/derived.rs +++ b/src/derived.rs @@ -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::QueryDescriptorSet; use crate::runtime::Revision; use crate::runtime::Runtime; use crate::runtime::RuntimeId; use crate::runtime::StampedValue; -use crate::CycleDetected; use crate::Database; -use crate::QueryDescriptor; -use crate::QueryFunction; -use crate::QueryStorageOps; -use crate::UncheckedMutQueryStorageOps; use log::debug; use parking_lot::Mutex; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; diff --git a/src/input.rs b/src/input.rs index 96d05b2..81fff76 100644 --- a/src/input.rs +++ b/src/input.rs @@ -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::Revision; use crate::runtime::StampedValue; -use crate::CycleDetected; use crate::Database; -use crate::InputQueryStorageOps; use crate::Query; -use crate::QueryStorageOps; -use crate::UncheckedMutQueryStorageOps; use log::debug; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use rustc_hash::FxHashMap; diff --git a/src/lib.rs b/src/lib.rs index a8441e7..682bda7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,30 @@ #![warn(rust_2018_idioms)] #![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 std::fmt::Debug; use std::hash::Hash; -pub mod debug; -pub mod derived; -pub mod input; -pub mod runtime; - pub use crate::runtime::Runtime; /// The base trait which your "query context" must implement. Gives /// access to the salsa runtime, which you must embed into your query /// 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. fn salsa_runtime(&self) -> &Runtime; @@ -25,9 +34,9 @@ pub trait Database: DatabaseStorageTypes { fn query(&self, query: Q) -> QueryTable<'_, Self, Q> where Q: Query, - Self: GetQueryTable, + Self: plumbing::GetQueryTable, { - >::get_query_table(self) + >::get_query_table(self) } } @@ -45,115 +54,10 @@ pub trait ParallelDatabase: Database + Send { 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; - - /// 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: 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: Query { - fn execute(db: &DB, key: Self::Key) -> Self::Value; -} - pub trait Query: Debug + Default + Sized + 'static { type Key: Clone + Debug + Hash + Eq; type Value: Clone + Debug + Hash + Eq; - type Storage: QueryStorageOps + Send + Sync; -} - -pub trait GetQueryTable>: Database { - fn get_query_table(db: &Self) -> QueryTable<'_, Self, Q>; -} - -pub trait QueryStorageOps: Default -where - DB: Database, - Q: Query, -{ - /// 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; - - /// 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: Default -where - DB: Database, - Q: Query, -{ - 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: Default -where - DB: Database, - Q: Query, -{ - fn set_unchecked(&self, db: &DB, key: &Q::Key, new_value: Q::Value); + type Storage: plumbing::QueryStorageOps + Send + Sync; } #[derive(new)] @@ -167,8 +71,6 @@ where descriptor_fn: fn(&DB, &Q::Key) -> DB::QueryDescriptor, } -pub struct CycleDetected; - impl QueryTable<'_, DB, Q> where DB: Database, @@ -187,7 +89,7 @@ where /// an active query computation. pub fn set(&self, key: Q::Key, value: Q::Value) where - Q::Storage: InputQueryStorageOps, + Q::Storage: plumbing::InputQueryStorageOps, { self.storage.set(self.db, &key, value); } @@ -197,7 +99,7 @@ where /// outside of an active query computation. pub fn set_constant(&self, key: Q::Key, value: Q::Value) where - Q::Storage: InputQueryStorageOps, + Q::Storage: plumbing::InputQueryStorageOps, { self.storage.set_constant(self.db, &key, value); } @@ -219,7 +121,7 @@ where /// and thus control what it sees when it executes. pub fn set_unchecked(&self, key: Q::Key, value: Q::Value) where - Q::Storage: UncheckedMutQueryStorageOps, + Q::Storage: plumbing::UncheckedMutQueryStorageOps, { 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])* fn $method_name(&self, key: $key_ty) -> $value_ty { - >::get_query_table(self) + >::get_query_table(self) .get(key) } )* @@ -384,7 +286,7 @@ macro_rules! query_group { query_type($QueryType:ty); ] ) => { - impl $crate::QueryFunction for $QueryType + impl $crate::plumbing::QueryFunction for $QueryType where DB: $DbTrait { fn execute(db: &DB, key: >::Key) @@ -420,25 +322,25 @@ macro_rules! query_group { ( @storage_ty[$DB:ident, $Self:ident, memoized] ) => { - $crate::derived::MemoizedStorage<$DB, $Self> + $crate::plumbing::MemoizedStorage<$DB, $Self> }; ( @storage_ty[$DB:ident, $Self:ident, volatile] ) => { - $crate::derived::VolatileStorage<$DB, $Self> + $crate::plumbing::VolatileStorage<$DB, $Self> }; ( @storage_ty[$DB:ident, $Self:ident, dependencies] ) => { - $crate::derived::DependencyStorage<$DB, $Self> + $crate::plumbing::DependencyStorage<$DB, $Self> }; ( @storage_ty[$DB:ident, $Self:ident, input] ) => { - $crate::input::InputStorage + $crate::plumbing::InputStorage }; } @@ -488,16 +390,16 @@ macro_rules! database_storage { )* } - impl $crate::DatabaseStorageTypes for $Database { + impl $crate::plumbing::DatabaseStorageTypes for $Database { type QueryDescriptor = __SalsaQueryDescriptor; type DatabaseStorage = $Storage; } - impl $crate::QueryDescriptor<$Database> for __SalsaQueryDescriptor { + impl $crate::plumbing::QueryDescriptor<$Database> for __SalsaQueryDescriptor { fn maybe_changed_since( &self, db: &$Database, - revision: $crate::runtime::Revision, + revision: $crate::plumbing::Revision, ) -> bool { match &self.kind { $( @@ -505,7 +407,7 @@ macro_rules! database_storage { __SalsaQueryDescriptorKind::$query_method(key) => { let runtime = $crate::Database::salsa_runtime(db); let storage = &runtime.storage().$query_method; - <_ as $crate::QueryStorageOps<$Database, $QueryType>>::maybe_changed_since( + <_ as $crate::plumbing::QueryStorageOps<$Database, $QueryType>>::maybe_changed_since( storage, db, revision, @@ -523,7 +425,7 @@ macro_rules! database_storage { impl $TraitName for $Database { } $( - impl $crate::GetQueryTable<$QueryType> for $Database { + impl $crate::plumbing::GetQueryTable<$QueryType> for $Database { fn get_query_table( db: &Self, ) -> $crate::QueryTable<'_, Self, $QueryType> { diff --git a/src/plumbing.rs b/src/plumbing.rs new file mode 100644 index 0000000..ed019bc --- /dev/null +++ b/src/plumbing.rs @@ -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; + + /// 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: 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: Query { + fn execute(db: &DB, key: Self::Key) -> Self::Value; +} + +pub trait GetQueryTable>: Database { + fn get_query_table(db: &Self) -> QueryTable<'_, Self, Q>; +} + +pub trait QueryStorageOps: Default +where + DB: Database, + Q: Query, +{ + /// 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; + + /// 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: Default +where + DB: Database, + Q: Query, +{ + 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: Default +where + DB: Database, + Q: Query, +{ + fn set_unchecked(&self, db: &DB, key: &Q::Key, new_value: Q::Value); +}