Merge pull request #242 from Marwes/lift_static_restriction

feat: Allow the dynamic db to be non-static
This commit is contained in:
Niko Matsakis 2020-09-09 10:52:50 -04:00 committed by GitHub
commit 2e2239a307
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 178 additions and 123 deletions

View file

@ -310,8 +310,8 @@ Therefore `QueryFunction` for example can become:
```rust,ignore
pub trait QueryFunction: Query {
fn execute(db: &Self::DynDb, key: Self::Key) -> Self::Value;
fn recover(db: &Self::DynDb, cycle: &[DB::DatabaseKey], key: &Self::Key) -> Option<Self::Value> {
fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
fn recover(db: &<Self as QueryDb<'_>>::DynDb, cycle: &[DB::DatabaseKey], key: &Self::Key) -> Option<Self::Value> {
let _ = (db, cycle, key);
None
}
@ -455,7 +455,7 @@ we have to make a few changes:
One downside of this proposal is that the `salsa::Database` trait now has a
`'static` bound. This is a result of the lack of GATs -- in particular, the
queries expect a `Q::DynDb` as argument. In the query definition, we have
queries expect a `<Q as QueryDb<'_>>::DynDb` as argument. In the query definition, we have
something like `type DynDb = dyn QueryGroupDatabase`, which in turn defaults to
`dyn::QueryGroupDatabase + 'static`.

View file

@ -262,7 +262,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
// query crate. Our experiments revealed that this makes a big
// difference in total compilation time in rust-analyzer, though
// it's not totally obvious why that should be.
fn __shim(db: &dyn #trait_name, #(#key_names: #keys),*) -> #value {
fn __shim(db: &(dyn #trait_name + '_), #(#key_names: #keys),*) -> #value {
salsa::plumbing::get_query_table::<#qt>(db).get((#(#key_names),*))
}
__shim(self, #(#key_names),*)
@ -461,23 +461,27 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
}
}
impl<'d> salsa::QueryDb<'d> for #qt
{
type DynDb = #dyn_db + 'd;
type Group = #group_struct;
type GroupStorage = #group_storage;
}
// ANCHOR:Query_impl
impl salsa::Query for #qt
{
type Key = (#(#keys),*);
type Value = #value;
type Storage = #storage;
type Group = #group_struct;
type GroupStorage = #group_storage;
type DynDb = #dyn_db;
const QUERY_INDEX: u16 = #query_index;
const QUERY_NAME: &'static str = #query_name;
fn query_storage(
group_storage: &Self::GroupStorage,
) -> &std::sync::Arc<Self::Storage> {
fn query_storage<'a>(
group_storage: &'a <Self as salsa::QueryDb<'_>>::GroupStorage,
) -> &'a std::sync::Arc<Self::Storage> {
&group_storage.#fn_name
}
}
@ -499,7 +503,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
let recover = if let Some(cycle_recovery_fn) = &query.cycle {
quote! {
fn recover(db: &Self::DynDb, cycle: &[salsa::DatabaseKeyIndex], #key_pattern: &<Self as salsa::Query>::Key)
fn recover(db: &<Self as salsa::QueryDb<'_>>::DynDb, cycle: &[salsa::DatabaseKeyIndex], #key_pattern: &<Self as salsa::Query>::Key)
-> Option<<Self as salsa::Query>::Value> {
Some(#cycle_recovery_fn(
db,
@ -516,7 +520,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
// ANCHOR:QueryFunction_impl
impl salsa::plumbing::QueryFunction for #qt
{
fn execute(db: &Self::DynDb, #key_pattern: <Self as salsa::Query>::Key)
fn execute(db: &<Self as salsa::QueryDb<'_>>::DynDb, #key_pattern: <Self as salsa::Query>::Key)
-> <Self as salsa::Query>::Value {
#invoke(db, #(#key_names),*)
}
@ -580,7 +584,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
impl #group_storage {
#trait_vis fn fmt_index(
&self,
db: &#dyn_db,
db: &(#dyn_db + '_),
input: salsa::DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
@ -592,7 +596,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
#trait_vis fn maybe_changed_since(
&self,
db: &#dyn_db,
db: &(#dyn_db + '_),
input: salsa::DatabaseKeyIndex,
revision: salsa::Revision,
) -> bool {

View file

@ -28,7 +28,7 @@ pub trait Compiler: Interner {
/// dolor,sit,amet,
/// consectetur,adipiscing,elit
/// ```
fn all_classes(db: &dyn Compiler) -> Arc<Vec<Class>> {
fn all_classes<'d>(db: &(dyn Compiler + 'd)) -> Arc<Vec<Class>> {
let string = db.input_string();
let rows = string.split('\n');
@ -53,13 +53,13 @@ fn all_classes(db: &dyn Compiler) -> Arc<Vec<Class>> {
Arc::new(classes)
}
fn fields(db: &dyn Compiler, class: Class) -> Arc<Vec<Field>> {
fn fields<'d>(db: &(dyn Compiler + 'd), class: Class) -> Arc<Vec<Field>> {
let class = db.lookup_intern_class(class);
let fields = class.fields.clone();
Arc::new(fields)
}
fn all_fields(db: &dyn Compiler) -> Arc<Vec<Field>> {
fn all_fields<'d>(db: &(dyn Compiler + 'd)) -> Arc<Vec<Field>> {
Arc::new(
db.all_classes()
.iter()

View file

@ -49,9 +49,10 @@ impl<K, V> TableEntry<K, V> {
}
}
impl<Q> DebugQueryTable for QueryTable<'_, Q>
impl<'d, Q> DebugQueryTable for QueryTable<'_, Q>
where
Q: Query,
Q::Storage: QueryStorageOps<Q>,
{
type Key = Q::Key;
type Value = Q::Value;

View file

@ -7,7 +7,7 @@ use crate::plumbing::QueryFunction;
use crate::plumbing::QueryStorageMassOps;
use crate::plumbing::QueryStorageOps;
use crate::runtime::{FxIndexMap, StampedValue};
use crate::{CycleError, Database, DatabaseKeyIndex, Revision, Runtime, SweepStrategy};
use crate::{CycleError, Database, DatabaseKeyIndex, QueryDb, Revision, Runtime, SweepStrategy};
use parking_lot::RwLock;
use std::convert::TryFrom;
use std::marker::PhantomData;
@ -48,7 +48,7 @@ where
{
}
pub trait MemoizationPolicy<Q>: Send + Sync + 'static
pub trait MemoizationPolicy<Q>: Send + Sync
where
Q: QueryFunction,
{
@ -126,7 +126,7 @@ where
fn fmt_index(
&self,
_db: &Q::DynDb,
_db: &<Q as QueryDb<'_>>::DynDb,
index: DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
@ -139,7 +139,7 @@ where
fn maybe_changed_since(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
input: DatabaseKeyIndex,
revision: Revision,
) -> bool {
@ -157,7 +157,7 @@ where
fn try_fetch(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
let slot = self.slot(key);
@ -177,11 +177,11 @@ where
Ok(value)
}
fn durability(&self, db: &Q::DynDb, key: &Q::Key) -> Durability {
fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability {
self.slot(key).durability(db)
}
fn entries<C>(&self, _db: &Q::DynDb) -> C
fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
where
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
{
@ -226,7 +226,7 @@ where
Q: QueryFunction,
MP: MemoizationPolicy<Q>,
{
fn invalidate(&self, db: &mut Q::DynDb, key: &Q::Key) {
fn invalidate(&self, db: &mut <Q as QueryDb<'_>>::DynDb, key: &Q::Key) {
db.salsa_runtime_mut()
.with_incremented_revision(&mut |_new_revision| {
let map_read = self.slot_map.read();

View file

@ -11,7 +11,8 @@ use crate::runtime::Runtime;
use crate::runtime::RuntimeId;
use crate::runtime::StampedValue;
use crate::{
CycleError, Database, DatabaseKeyIndex, DiscardIf, DiscardWhat, Event, EventKind, SweepStrategy,
CycleError, Database, DatabaseKeyIndex, DiscardIf, DiscardWhat, Event, EventKind, QueryDb,
SweepStrategy,
};
use log::{debug, info};
use parking_lot::Mutex;
@ -125,7 +126,7 @@ where
pub(super) fn read(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
) -> Result<StampedValue<Q::Value>, CycleError<DatabaseKeyIndex>> {
let runtime = db.salsa_runtime();
@ -153,7 +154,7 @@ where
/// shows a potentially out of date value.
fn read_upgrade(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
revision_now: Revision,
) -> Result<StampedValue<Q::Value>, CycleError<DatabaseKeyIndex>> {
let runtime = db.salsa_runtime();
@ -326,7 +327,7 @@ where
/// Note that in case `ProbeState::UpToDate`, the lock will have been released.
fn probe<StateGuard>(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
state: StateGuard,
runtime: &Runtime,
revision_now: Revision,
@ -419,7 +420,7 @@ where
ProbeState::StaleOrAbsent(state)
}
pub(super) fn durability(&self, db: &Q::DynDb) -> Durability {
pub(super) fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb) -> Durability {
match &*self.state.read() {
QueryState::NotComputed => Durability::LOW,
QueryState::InProgress { .. } => panic!("query in progress"),
@ -532,7 +533,11 @@ where
}
}
pub(super) fn maybe_changed_since(&self, db: &Q::DynDb, revision: Revision) -> bool {
pub(super) fn maybe_changed_since(
&self,
db: &<Q as QueryDb<'_>>::DynDb,
revision: Revision,
) -> bool {
let runtime = db.salsa_runtime();
let revision_now = runtime.current_revision();
@ -721,7 +726,7 @@ where
/// computed (but first drop the lock on the map).
fn register_with_in_progress_thread(
&self,
_db: &Q::DynDb,
_db: &<Q as QueryDb<'_>>::DynDb,
runtime: &Runtime,
other_id: RuntimeId,
waiting: &Mutex<SmallVec<[Promise<WaitResult<Q::Value, DatabaseKeyIndex>>; 2]>>,
@ -886,7 +891,7 @@ where
{
fn validate_memoized_value(
&mut self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
revision_now: Revision,
) -> Option<StampedValue<Q::Value>> {
// If we don't have a memoized value, nothing to validate.
@ -1032,8 +1037,8 @@ where
#[allow(dead_code)]
fn check_static<Q, MP>()
where
Q: QueryFunction,
MP: MemoizationPolicy<Q>,
Q: QueryFunction + 'static,
MP: MemoizationPolicy<Q> + 'static,
Q::Key: 'static,
Q::Value: 'static,
{

View file

@ -8,7 +8,7 @@ use crate::runtime::{FxIndexMap, StampedValue};
use crate::CycleError;
use crate::Database;
use crate::Query;
use crate::{DatabaseKeyIndex, Runtime, SweepStrategy};
use crate::{DatabaseKeyIndex, QueryDb, Runtime, SweepStrategy};
use indexmap::map::Entry;
use log::debug;
use parking_lot::RwLock;
@ -65,7 +65,7 @@ where
fn fmt_index(
&self,
_db: &Q::DynDb,
_db: &<Q as QueryDb<'_>>::DynDb,
index: DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
@ -78,7 +78,7 @@ where
fn maybe_changed_since(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
input: DatabaseKeyIndex,
revision: Revision,
) -> bool {
@ -96,7 +96,7 @@ where
fn try_fetch(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
let slot = self
@ -115,14 +115,14 @@ where
Ok(value)
}
fn durability(&self, _db: &Q::DynDb, key: &Q::Key) -> Durability {
fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability {
match self.slot(key) {
Some(slot) => slot.stamped_value.read().durability,
None => panic!("no value set for {:?}({:?})", Q::default(), key),
}
}
fn entries<C>(&self, _db: &Q::DynDb) -> C
fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
where
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
{
@ -143,7 +143,7 @@ impl<Q> Slot<Q>
where
Q: Query,
{
fn maybe_changed_since(&self, _db: &Q::DynDb, revision: Revision) -> bool {
fn maybe_changed_since(&self, _db: &<Q as QueryDb<'_>>::DynDb, revision: Revision) -> bool {
debug!(
"maybe_changed_since(slot={:?}, revision={:?})",
self, revision,
@ -171,7 +171,13 @@ impl<Q> InputQueryStorageOps<Q> for InputStorage<Q>
where
Q: Query,
{
fn set(&self, db: &mut Q::DynDb, key: &Q::Key, value: Q::Value, durability: Durability) {
fn set(
&self,
db: &mut <Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
value: Q::Value,
durability: Durability,
) {
log::debug!(
"{:?}({:?}) = {:?} ({:?})",
Q::default(),
@ -257,7 +263,7 @@ where
#[allow(dead_code)]
fn check_static<Q>()
where
Q: Query,
Q: Query + 'static,
Q::Key: 'static,
Q::Value: 'static,
{

View file

@ -6,7 +6,7 @@ use crate::plumbing::QueryStorageMassOps;
use crate::plumbing::QueryStorageOps;
use crate::revision::Revision;
use crate::Query;
use crate::{CycleError, Database, DatabaseKeyIndex, DiscardIf, Runtime, SweepStrategy};
use crate::{CycleError, Database, DatabaseKeyIndex, DiscardIf, QueryDb, Runtime, SweepStrategy};
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::RwLock;
use rustc_hash::FxHashMap;
@ -35,13 +35,6 @@ where
Q: Query,
Q::Key: InternKey,
Q::Value: Eq + Hash,
IQ: Query<
Key = Q::Value,
Value = Q::Key,
Group = Q::Group,
DynDb = Q::DynDb,
GroupStorage = Q::GroupStorage,
>,
{
phantom: std::marker::PhantomData<(Q::Key, IQ)>,
}
@ -186,7 +179,7 @@ where
/// In either case, the `accessed_at` field of the slot is updated
/// to the current revision, ensuring that the slot cannot be GC'd
/// while the current queries execute.
fn intern_index(&self, db: &Q::DynDb, key: &Q::Key) -> Arc<Slot<Q::Key>> {
fn intern_index(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Arc<Slot<Q::Key>> {
if let Some(i) = self.intern_check(db, key) {
return i;
}
@ -268,7 +261,11 @@ where
slot
}
fn intern_check(&self, db: &Q::DynDb, key: &Q::Key) -> Option<Arc<Slot<Q::Key>>> {
fn intern_check(
&self,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Option<Arc<Slot<Q::Key>>> {
let revision_now = db.salsa_runtime().current_revision();
let slot = self.tables.read().slot_for_key(key, revision_now)?;
Some(slot)
@ -276,7 +273,7 @@ where
/// Given an index, lookup and clone its value, updating the
/// `accessed_at` time if necessary.
fn lookup_value(&self, db: &Q::DynDb, index: InternId) -> Arc<Slot<Q::Key>> {
fn lookup_value(&self, db: &<Q as QueryDb<'_>>::DynDb, index: InternId) -> Arc<Slot<Q::Key>> {
let revision_now = db.salsa_runtime().current_revision();
self.tables.read().slot_for_index(index, revision_now)
}
@ -296,7 +293,7 @@ where
fn fmt_index(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
index: DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
@ -309,7 +306,7 @@ where
fn maybe_changed_since(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
input: DatabaseKeyIndex,
revision: Revision,
) -> bool {
@ -322,7 +319,7 @@ where
fn try_fetch(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
let slot = self.intern_index(db, key);
@ -336,11 +333,11 @@ where
Ok(<Q::Value>::from_intern_id(index))
}
fn durability(&self, _db: &Q::DynDb, _key: &Q::Key) -> Durability {
fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, _key: &Q::Key) -> Durability {
INTERN_DURABILITY
}
fn entries<C>(&self, _db: &Q::DynDb) -> C
fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
where
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
{
@ -412,19 +409,46 @@ where
}
}
// Workaround for
// ```
// IQ: for<'d> QueryDb<
// 'd,
// DynDb = <Q as QueryDb<'d>>::DynDb,
// Group = <Q as QueryDb<'d>>::Group,
// GroupStorage = <Q as QueryDb<'d>>::GroupStorage,
// >,
// ```
// not working to make rustc know DynDb, Group and GroupStorage being the same in `Q` and `IQ`
#[doc(hidden)]
pub trait EqualDynDb<'d, IQ>: QueryDb<'d>
where
IQ: QueryDb<'d>,
{
fn convert_db(d: &Self::DynDb) -> &IQ::DynDb;
fn convert_group_storage(d: &Self::GroupStorage) -> &IQ::GroupStorage;
}
impl<'d, IQ, Q> EqualDynDb<'d, IQ> for Q
where
Q: QueryDb<'d, DynDb = IQ::DynDb, Group = IQ::Group, GroupStorage = IQ::GroupStorage>,
Q::DynDb: HasQueryGroup<Q::Group>,
IQ: QueryDb<'d>,
{
fn convert_db(d: &Self::DynDb) -> &IQ::DynDb {
d
}
fn convert_group_storage(d: &Self::GroupStorage) -> &IQ::GroupStorage {
d
}
}
impl<Q, IQ> QueryStorageOps<Q> for LookupInternedStorage<Q, IQ>
where
Q: Query,
Q::Key: InternKey,
Q::Value: Eq + Hash,
IQ: Query<
Key = Q::Value,
Value = Q::Key,
Storage = InternedStorage<IQ>,
Group = Q::Group,
DynDb = Q::DynDb,
GroupStorage = Q::GroupStorage,
>,
IQ: Query<Key = Q::Value, Value = Q::Key, Storage = InternedStorage<IQ>>,
for<'d> Q: EqualDynDb<'d, IQ>,
{
fn new(_group_index: u16) -> Self {
LookupInternedStorage {
@ -434,35 +458,38 @@ where
fn fmt_index(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
index: DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result {
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(group_storage);
interned_storage.fmt_index(db, index, fmt)
let group_storage =
<<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
interned_storage.fmt_index(Q::convert_db(db), index, fmt)
}
fn maybe_changed_since(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
input: DatabaseKeyIndex,
revision: Revision,
) -> bool {
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(group_storage);
interned_storage.maybe_changed_since(db, input, revision)
let group_storage =
<<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
interned_storage.maybe_changed_since(Q::convert_db(db), input, revision)
}
fn try_fetch(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
let index = key.as_intern_id();
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(group_storage);
let slot = interned_storage.lookup_value(db, index);
let group_storage =
<<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
let slot = interned_storage.lookup_value(Q::convert_db(db), index);
let value = slot.value.clone();
let interned_at = slot.interned_at;
db.salsa_runtime().report_query_read(
@ -473,16 +500,17 @@ where
Ok(value)
}
fn durability(&self, _db: &Q::DynDb, _key: &Q::Key) -> Durability {
fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, _key: &Q::Key) -> Durability {
INTERN_DURABILITY
}
fn entries<C>(&self, db: &Q::DynDb) -> C
fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
where
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
{
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(group_storage);
let group_storage =
<<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
let tables = interned_storage.tables.read();
tables
.map
@ -499,13 +527,7 @@ where
Q: Query,
Q::Key: InternKey,
Q::Value: Eq + Hash,
IQ: Query<
Key = Q::Value,
Value = Q::Key,
Group = Q::Group,
DynDb = Q::DynDb,
GroupStorage = Q::GroupStorage,
>,
IQ: Query<Key = Q::Value, Value = Q::Key>,
{
fn sweep(&self, _: &Runtime, _strategy: SweepStrategy) {}
fn purge(&self) {}

View file

@ -45,7 +45,7 @@ pub use crate::storage::Storage;
/// 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: 'static + plumbing::DatabaseOps {
pub trait Database: plumbing::DatabaseOps {
/// Iterates through all query storage and removes any values that
/// have not been used since the last revision was created. The
/// intended use-cycle is that you first execute all of your
@ -421,7 +421,22 @@ where
/// Trait implements by all of the "special types" associated with
/// each of your queries.
pub trait Query: Debug + Default + Sized + 'static {
///
/// Base trait of `Query` that has a lifetime parameter to allow the `DynDb` to be non-'static.
pub trait QueryDb<'d>: Sized {
/// Dyn version of the associated trait for this query group.
type DynDb: ?Sized + Database + HasQueryGroup<Self::Group> + 'd;
/// Associate query group struct.
type Group: plumbing::QueryGroup<GroupStorage = Self::GroupStorage>;
/// Generated struct that contains storage for all queries in a group.
type GroupStorage;
}
/// Trait implements by all of the "special types" associated with
/// each of your queries.
pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
/// Type that you you give as a parameter -- for queries with zero
/// or more than one input, this will be a tuple.
type Key: Clone + Debug + Hash + Eq;
@ -430,16 +445,8 @@ pub trait Query: Debug + Default + Sized + 'static {
type Value: Clone + Debug;
/// Internal struct storing the values for the query.
type Storage: plumbing::QueryStorageOps<Self>;
/// Associate query group struct.
type Group: plumbing::QueryGroup<DynDb = Self::DynDb, GroupStorage = Self::GroupStorage>;
/// Generated struct that contains storage for all queries in a group.
type GroupStorage;
/// Dyn version of the associated trait for this query group.
type DynDb: ?Sized + Database + HasQueryGroup<Self::Group>;
// type Storage: plumbing::QueryStorageOps<Self>;
type Storage;
/// A unique index identifying this query within the group.
const QUERY_INDEX: u16;
@ -448,7 +455,9 @@ pub trait Query: Debug + Default + Sized + 'static {
const QUERY_NAME: &'static str;
/// Extact storage for this query from the storage for its group.
fn query_storage(group_storage: &Self::GroupStorage) -> &Arc<Self::Storage>;
fn query_storage<'a>(
group_storage: &'a <Self as QueryDb<'_>>::GroupStorage,
) -> &'a Arc<Self::Storage>;
}
/// Return value from [the `query` method] on `Database`.
@ -457,18 +466,19 @@ pub trait Query: Debug + Default + Sized + 'static {
/// [the `query` method]: trait.Database.html#method.query
pub struct QueryTable<'me, Q>
where
Q: Query + 'me,
Q: Query,
{
db: &'me Q::DynDb,
db: &'me <Q as QueryDb<'me>>::DynDb,
storage: &'me Q::Storage,
}
impl<'me, Q> QueryTable<'me, Q>
where
Q: Query,
Q::Storage: QueryStorageOps<Q>,
{
/// Constructs a new `QueryTable`.
pub fn new(db: &'me Q::DynDb, storage: &'me Q::Storage) -> Self {
pub fn new(db: &'me <Q as QueryDb<'me>>::DynDb, storage: &'me Q::Storage) -> Self {
Self { db, storage }
}
@ -514,7 +524,7 @@ pub struct QueryTableMut<'me, Q>
where
Q: Query + 'me,
{
db: &'me mut Q::DynDb,
db: &'me mut <Q as QueryDb<'me>>::DynDb,
storage: Arc<Q::Storage>,
}
@ -523,7 +533,7 @@ where
Q: Query,
{
/// Constructs a new `QueryTableMut`.
pub fn new(db: &'me mut Q::DynDb, storage: Arc<Q::Storage>) -> Self {
pub fn new(db: &'me mut <Q as QueryDb<'me>>::DynDb, storage: Arc<Q::Storage>) -> Self {
Self { db, storage }
}

View file

@ -17,7 +17,7 @@ pub use crate::derived::MemoizedStorage;
pub use crate::input::InputStorage;
pub use crate::interned::InternedStorage;
pub use crate::interned::LookupInternedStorage;
pub use crate::{revision::Revision, DatabaseKeyIndex, Runtime};
pub use crate::{revision::Revision, DatabaseKeyIndex, QueryDb, Runtime};
#[derive(Clone, Debug)]
pub struct CycleDetected {
@ -72,10 +72,10 @@ pub trait QueryStorageMassOps {
pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
pub trait QueryFunction: Query {
fn execute(db: &Self::DynDb, key: Self::Key) -> Self::Value;
fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
fn recover(
db: &Self::DynDb,
db: &<Self as QueryDb<'_>>::DynDb,
cycle: &[DatabaseKeyIndex],
key: &Self::Key,
) -> Option<Self::Value> {
@ -86,9 +86,10 @@ pub trait QueryFunction: Query {
/// Create a query table, which has access to the storage for the query
/// and offers methods like `get`.
pub fn get_query_table<Q>(db: &Q::DynDb) -> QueryTable<'_, Q>
pub fn get_query_table<'me, Q>(db: &'me <Q as QueryDb<'me>>::DynDb) -> QueryTable<'me, Q>
where
Q: Query,
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);
@ -97,7 +98,7 @@ where
/// 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<Q>(db: &mut Q::DynDb) -> QueryTableMut<'_, Q>
pub fn get_query_table_mut<'me, Q>(db: &'me mut <Q as QueryDb<'me>>::DynDb) -> QueryTableMut<'me, Q>
where
Q: Query,
{
@ -133,7 +134,7 @@ where
/// Format a database key index in a suitable way.
fn fmt_index(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
index: DatabaseKeyIndex,
fmt: &mut std::fmt::Formatter<'_>,
) -> std::fmt::Result;
@ -142,7 +143,7 @@ where
/// changed since the given revision.
fn maybe_changed_since(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
input: DatabaseKeyIndex,
revision: Revision,
) -> bool;
@ -156,15 +157,15 @@ where
/// itself.
fn try_fetch(
&self,
db: &Q::DynDb,
db: &<Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>>;
/// Returns the durability associated with a given key.
fn durability(&self, db: &Q::DynDb, key: &Q::Key) -> Durability;
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::DynDb) -> C
fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
where
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
}
@ -176,7 +177,13 @@ pub trait InputQueryStorageOps<Q>
where
Q: Query,
{
fn set(&self, db: &mut Q::DynDb, key: &Q::Key, new_value: Q::Value, durability: Durability);
fn set(
&self,
db: &mut <Q as QueryDb<'_>>::DynDb,
key: &Q::Key,
new_value: Q::Value,
durability: Durability,
);
}
/// An optional trait that is implemented for "user mutable" storage:
@ -190,5 +197,5 @@ pub trait DerivedQueryStorageOps<Q>
where
Q: Query,
{
fn invalidate(&self, db: &mut Q::DynDb, key: &Q::Key);
fn invalidate(&self, db: &mut <Q as QueryDb<'_>>::DynDb, key: &Q::Key);
}