mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-22 21:05:11 +00:00
Merge pull request #242 from Marwes/lift_static_restriction
feat: Allow the dynamic db to be non-static
This commit is contained in:
commit
2e2239a307
10 changed files with 178 additions and 123 deletions
|
@ -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`.
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
{
|
||||
|
|
24
src/input.rs
24
src/input.rs
|
@ -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,
|
||||
{
|
||||
|
|
116
src/interned.rs
116
src/interned.rs
|
@ -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) {}
|
||||
|
|
46
src/lib.rs
46
src/lib.rs
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue