mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-13 00:40:22 +00:00
switch to new database design
Under this design, *all* databases are a `DatabaseImpl<U>`, where the `U` implements `UserData` (you can use `()` if there is none). Code would default to `&dyn salsa::Database` but if you want to give access to the userdata, you can define a custom database trait `MyDatabase: salsa::Databse` so long as you * annotate `MyDatabase` trait definition of impls of `MyDatabase` with `#[salsa::db]` * implement `MyDatabase` for `DatabaseImpl<U>` where `U` is your userdata (this could be a blanket impl, if you don't know the precise userdata type). The `tests/common/mod.rs` shows the pattern.
This commit is contained in:
parent
64556e9d28
commit
daaa78056a
77 changed files with 491 additions and 1125 deletions
|
@ -26,7 +26,7 @@ fn many_tracked_structs(criterion: &mut Criterion) {
|
|||
criterion.bench_function("many_tracked_structs", |b| {
|
||||
b.iter_batched_ref(
|
||||
|| {
|
||||
let db = salsa::default_database();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = Input::new(&db, 1_000);
|
||||
let input2 = Input::new(&db, 1);
|
||||
|
|
|
@ -32,13 +32,6 @@ struct DbMacro {
|
|||
impl DbMacro {
|
||||
fn try_db(self, input: syn::Item) -> syn::Result<TokenStream> {
|
||||
match input {
|
||||
syn::Item::Struct(input) => {
|
||||
let has_storage_impl = self.zalsa_database_impl(&input)?;
|
||||
Ok(quote! {
|
||||
#has_storage_impl
|
||||
#input
|
||||
})
|
||||
}
|
||||
syn::Item::Trait(mut input) => {
|
||||
self.add_salsa_view_method(&mut input)?;
|
||||
Ok(quote! {
|
||||
|
@ -53,54 +46,11 @@ impl DbMacro {
|
|||
}
|
||||
_ => Err(syn::Error::new_spanned(
|
||||
input,
|
||||
"`db` must be applied to a struct, trait, or impl",
|
||||
"`db` must be applied to a trait or impl",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn find_storage_field(&self, input: &syn::ItemStruct) -> syn::Result<syn::Ident> {
|
||||
let storage = "storage";
|
||||
for field in input.fields.iter() {
|
||||
if let Some(i) = &field.ident {
|
||||
if i == storage {
|
||||
return Ok(i.clone());
|
||||
}
|
||||
} else {
|
||||
return Err(syn::Error::new_spanned(
|
||||
field,
|
||||
"database struct must be a braced struct (`{}`) with a field named `storage`",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Err(syn::Error::new_spanned(
|
||||
&input.ident,
|
||||
"database struct must be a braced struct (`{}`) with a field named `storage`",
|
||||
))
|
||||
}
|
||||
|
||||
fn zalsa_database_impl(&self, input: &syn::ItemStruct) -> syn::Result<TokenStream> {
|
||||
let storage = self.find_storage_field(input)?;
|
||||
let db = &input.ident;
|
||||
let zalsa = self.hygiene.ident("zalsa");
|
||||
|
||||
Ok(quote! {
|
||||
const _: () = {
|
||||
use salsa::plumbing as #zalsa;
|
||||
|
||||
unsafe impl #zalsa::ZalsaDatabase for #db {
|
||||
fn zalsa(&self) -> &dyn #zalsa::Zalsa {
|
||||
&self.#storage
|
||||
}
|
||||
|
||||
fn zalsa_mut(&mut self) -> &mut dyn #zalsa::Zalsa {
|
||||
&mut self.#storage
|
||||
}
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn add_salsa_view_method(&self, input: &mut syn::ItemTrait) -> syn::Result<()> {
|
||||
input.items.push(parse_quote! {
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -1,49 +1,48 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use salsa::UserData;
|
||||
|
||||
pub type CalcDatabaseImpl = salsa::DatabaseImpl<Calc>;
|
||||
|
||||
// ANCHOR: db_struct
|
||||
#[derive(Default)]
|
||||
#[salsa::db]
|
||||
pub(crate) struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
|
||||
pub struct Calc {
|
||||
// The logs are only used for testing and demonstrating reuse:
|
||||
//
|
||||
logs: Option<Arc<Mutex<Vec<String>>>>,
|
||||
logs: Arc<Mutex<Option<Vec<String>>>>,
|
||||
}
|
||||
// ANCHOR_END: db_struct
|
||||
|
||||
impl Database {
|
||||
impl Calc {
|
||||
/// Enable logging of each salsa event.
|
||||
#[cfg(test)]
|
||||
pub fn enable_logging(self) -> Self {
|
||||
assert!(self.logs.is_none());
|
||||
Self {
|
||||
storage: self.storage,
|
||||
logs: Some(Default::default()),
|
||||
pub fn enable_logging(&self) {
|
||||
let mut logs = self.logs.lock().unwrap();
|
||||
if logs.is_none() {
|
||||
*logs = Some(vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn take_logs(&mut self) -> Vec<String> {
|
||||
if let Some(logs) = &self.logs {
|
||||
std::mem::take(&mut *logs.lock().unwrap())
|
||||
pub fn take_logs(&self) -> Vec<String> {
|
||||
let mut logs = self.logs.lock().unwrap();
|
||||
if let Some(logs) = &mut *logs {
|
||||
std::mem::take(logs)
|
||||
} else {
|
||||
panic!("logs not enabled");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANCHOR: db_impl
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
impl UserData for Calc {
|
||||
fn salsa_event(db: &CalcDatabaseImpl, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
eprintln!("Event: {event:?}");
|
||||
// Log interesting events, if logging is enabled
|
||||
if let Some(logs) = &self.logs {
|
||||
// don't log boring events
|
||||
if let Some(logs) = &mut *db.logs.lock().unwrap() {
|
||||
// only log interesting events
|
||||
if let salsa::EventKind::WillExecute { .. } = event.kind {
|
||||
logs.lock().unwrap().push(format!("Event: {event:?}"));
|
||||
logs.push(format!("Event: {event:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use db::CalcDatabaseImpl;
|
||||
use ir::{Diagnostic, SourceProgram};
|
||||
use salsa::Database as Db;
|
||||
|
||||
|
@ -8,7 +9,7 @@ mod parser;
|
|||
mod type_check;
|
||||
|
||||
pub fn main() {
|
||||
let db = db::Database::default();
|
||||
let db: CalcDatabaseImpl = Default::default();
|
||||
let source_program = SourceProgram::new(&db, String::new());
|
||||
compile::compile(&db, source_program);
|
||||
let diagnostics = compile::compile::accumulated::<Diagnostic>(&db, source_program);
|
||||
|
|
|
@ -351,9 +351,11 @@ impl<'db> Parser<'_, 'db> {
|
|||
/// Returns the statements and the diagnostics generated.
|
||||
#[cfg(test)]
|
||||
fn parse_string(source_text: &str) -> String {
|
||||
use salsa::Database as _;
|
||||
use salsa::Database;
|
||||
|
||||
crate::db::Database::default().attach(|db| {
|
||||
use crate::db::CalcDatabaseImpl;
|
||||
|
||||
CalcDatabaseImpl::default().attach(|db| {
|
||||
// Create the source program
|
||||
let source_program = SourceProgram::new(db, source_text.to_string());
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ use derive_new::new;
|
|||
use expect_test::expect;
|
||||
use salsa::Accumulator;
|
||||
#[cfg(test)]
|
||||
use salsa::Database as _;
|
||||
#[cfg(test)]
|
||||
use test_log::test;
|
||||
|
||||
// ANCHOR: parse_statements
|
||||
|
@ -100,12 +98,13 @@ fn check_string(
|
|||
expected_diagnostics: expect_test::Expect,
|
||||
edits: &[(&str, expect_test::Expect, expect_test::Expect)],
|
||||
) {
|
||||
use salsa::Setter;
|
||||
use salsa::{Database, Setter};
|
||||
|
||||
use crate::{db::Database, ir::SourceProgram, parser::parse_statements};
|
||||
use crate::{db::CalcDatabaseImpl, ir::SourceProgram, parser::parse_statements};
|
||||
|
||||
// Create the database
|
||||
let mut db = Database::default().enable_logging();
|
||||
let mut db = CalcDatabaseImpl::default();
|
||||
db.enable_logging();
|
||||
|
||||
// Create the source program
|
||||
let source_program = SourceProgram::new(&db, source_text.to_string());
|
||||
|
|
|
@ -8,13 +8,13 @@ use notify_debouncer_mini::{
|
|||
notify::{RecommendedWatcher, RecursiveMode},
|
||||
DebounceEventResult, Debouncer,
|
||||
};
|
||||
use salsa::{Accumulator, Setter};
|
||||
use salsa::{Accumulator, DatabaseImpl, Setter, UserData};
|
||||
|
||||
// ANCHOR: main
|
||||
fn main() -> Result<()> {
|
||||
// Create the channel to receive file change events.
|
||||
let (tx, rx) = unbounded();
|
||||
let mut db = Database::new(tx);
|
||||
let mut db = DatabaseImpl::with(LazyInput::new(tx));
|
||||
|
||||
let initial_file_path = std::env::args_os()
|
||||
.nth(1)
|
||||
|
@ -74,19 +74,15 @@ trait Db: salsa::Database {
|
|||
fn input(&self, path: PathBuf) -> Result<File>;
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
struct LazyInput {
|
||||
logs: Mutex<Vec<String>>,
|
||||
files: DashMap<PathBuf, File>,
|
||||
file_watcher: Mutex<Debouncer<RecommendedWatcher>>,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
impl LazyInput {
|
||||
fn new(tx: Sender<DebounceEventResult>) -> Self {
|
||||
let storage = Default::default();
|
||||
Self {
|
||||
storage,
|
||||
logs: Default::default(),
|
||||
files: DashMap::new(),
|
||||
file_watcher: Mutex::new(new_debouncer(Duration::from_secs(1), tx).unwrap()),
|
||||
|
@ -94,8 +90,18 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
impl UserData for LazyInput {
|
||||
fn salsa_event(db: &DatabaseImpl<Self>, event: &dyn Fn() -> salsa::Event) {
|
||||
// don't log boring events
|
||||
let event = event();
|
||||
if let salsa::EventKind::WillExecute { .. } = event.kind {
|
||||
db.logs.lock().unwrap().push(format!("{:?}", event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {
|
||||
impl Db for DatabaseImpl<LazyInput> {
|
||||
fn input(&self, path: PathBuf) -> Result<File> {
|
||||
let path = path
|
||||
.canonicalize()
|
||||
|
@ -122,17 +128,6 @@ impl Db for Database {
|
|||
}
|
||||
// ANCHOR_END: db
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
// don't log boring events
|
||||
let event = event();
|
||||
if let salsa::EventKind::WillExecute { .. } = event.kind {
|
||||
self.logs.lock().unwrap().push(format!("{:?}", event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::accumulator]
|
||||
struct Diagnostic(String);
|
||||
|
||||
|
|
109
src/database.rs
109
src/database.rs
|
@ -1,20 +1,24 @@
|
|||
use crate::{local_state, storage::ZalsaDatabase, Durability, Event, Revision};
|
||||
use std::{any::Any, panic::RefUnwindSafe};
|
||||
|
||||
use crate::{self as salsa, local_state, storage::Zalsa, Durability, Event, Revision, Storage};
|
||||
|
||||
/// The trait implemented by all Salsa databases.
|
||||
/// You can create your own subtraits of this trait using the `#[salsa::db]` procedural macro.
|
||||
///
|
||||
/// # Safety conditions
|
||||
///
|
||||
/// This trait can only safely be implemented by Salsa's [`DatabaseImpl`][] type.
|
||||
/// FIXME: Document better the unsafety conditions we guarantee.
|
||||
#[salsa_macros::db]
|
||||
pub trait Database: ZalsaDatabase + AsDynDatabase {
|
||||
/// This function is invoked at key points in the salsa
|
||||
/// runtime. It permits the database to be customized and to
|
||||
/// inject logging or other custom behavior.
|
||||
///
|
||||
/// By default, the event is logged at level debug using
|
||||
/// the standard `log` facade.
|
||||
pub unsafe trait Database: AsDynDatabase + Any {
|
||||
/// This function is invoked by the salsa runtime at various points during execution.
|
||||
/// You can customize what happens by implementing the [`UserData`][] trait.
|
||||
/// By default, the event is logged at level debug using tracing facade.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `event`, a fn that, if called, will create the event that occurred
|
||||
fn salsa_event(&self, event: &dyn Fn() -> Event) {
|
||||
tracing::debug!("salsa_event: {:?}", event())
|
||||
}
|
||||
fn salsa_event(&self, event: &dyn Fn() -> Event);
|
||||
|
||||
/// A "synthetic write" causes the system to act *as though* some
|
||||
/// input of durability `durability` has changed. This is mostly
|
||||
|
@ -48,6 +52,13 @@ pub trait Database: ZalsaDatabase + AsDynDatabase {
|
|||
{
|
||||
local_state::attach(self, |_state| op(self))
|
||||
}
|
||||
|
||||
/// Plumbing methods.
|
||||
#[doc(hidden)]
|
||||
fn zalsa(&self) -> &dyn Zalsa;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn zalsa_mut(&mut self) -> &mut dyn Zalsa;
|
||||
}
|
||||
|
||||
/// Upcast to a `dyn Database`.
|
||||
|
@ -83,3 +94,79 @@ impl dyn Database {
|
|||
self.zalsa().views().try_view_as(self).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete implementation of the [`Database`][] trait.
|
||||
/// Takes an optional type parameter `U` that allows you to thread your own data.
|
||||
pub struct DatabaseImpl<U: UserData = ()> {
|
||||
storage: Storage<U>,
|
||||
}
|
||||
|
||||
impl<U: UserData + Default> Default for DatabaseImpl<U> {
|
||||
fn default() -> Self {
|
||||
Self::with(U::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl DatabaseImpl<()> {
|
||||
/// Create a new database with the given user data.
|
||||
///
|
||||
/// You can also use the [`Default`][] trait if your userdata implements it.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
storage: Storage::with(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<U: UserData> DatabaseImpl<U> {
|
||||
/// Create a new database with the given user data.
|
||||
///
|
||||
/// You can also use the [`Default`][] trait if your userdata implements it.
|
||||
pub fn with(u: U) -> Self {
|
||||
Self {
|
||||
storage: Storage::with(u),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<U: UserData> std::ops::Deref for DatabaseImpl<U> {
|
||||
type Target = U;
|
||||
|
||||
fn deref(&self) -> &U {
|
||||
&self.storage.user_data()
|
||||
}
|
||||
}
|
||||
|
||||
impl<U: UserData + RefUnwindSafe> RefUnwindSafe for DatabaseImpl<U> {}
|
||||
|
||||
#[salsa_macros::db]
|
||||
unsafe impl<U: UserData> Database for DatabaseImpl<U> {
|
||||
fn zalsa(&self) -> &dyn Zalsa {
|
||||
&self.storage
|
||||
}
|
||||
|
||||
fn zalsa_mut(&mut self) -> &mut dyn Zalsa {
|
||||
&mut self.storage
|
||||
}
|
||||
|
||||
// Report a salsa event.
|
||||
fn salsa_event(&self, event: &dyn Fn() -> Event) {
|
||||
U::salsa_event(self, event)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait UserData: Any + Sized {
|
||||
/// Callback invoked by the [`Database`][] at key points during salsa execution.
|
||||
/// By overriding this method, you can inject logging or other custom behavior.
|
||||
///
|
||||
/// By default, the event is logged at level debug using the `tracing` crate.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `event` a fn that, if called, will return the event that occurred
|
||||
fn salsa_event(_db: &DatabaseImpl<Self>, event: &dyn Fn() -> Event) {
|
||||
tracing::debug!("salsa_event: {:?}", event())
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for () {}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::{
|
||||
accumulator, hash::FxHashSet, local_state, storage::ZalsaDatabase as _, DatabaseKeyIndex, Id,
|
||||
};
|
||||
use crate::{accumulator, hash::FxHashSet, local_state, Database, DatabaseKeyIndex, Id};
|
||||
|
||||
use super::{Configuration, IngredientImpl};
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
local_state::ActiveQueryGuard, runtime::StampedValue, storage::ZalsaDatabase, Cycle, Database,
|
||||
Event, EventKind,
|
||||
local_state::ActiveQueryGuard, runtime::StampedValue, Cycle, Database, Event, EventKind,
|
||||
};
|
||||
|
||||
use super::{memo::Memo, Configuration, IngredientImpl};
|
||||
|
|
|
@ -3,8 +3,7 @@ use arc_swap::Guard;
|
|||
use crate::{
|
||||
local_state::{self, LocalState},
|
||||
runtime::StampedValue,
|
||||
storage::ZalsaDatabase as _,
|
||||
AsDynDatabase as _, Id,
|
||||
AsDynDatabase as _, Database as _, Id,
|
||||
};
|
||||
|
||||
use super::{Configuration, IngredientImpl};
|
||||
|
|
|
@ -4,8 +4,8 @@ use crate::{
|
|||
key::DatabaseKeyIndex,
|
||||
local_state::{self, ActiveQueryGuard, EdgeKind, LocalState, QueryOrigin},
|
||||
runtime::StampedValue,
|
||||
storage::{Zalsa, ZalsaDatabase as _},
|
||||
AsDynDatabase as _, Id, Revision,
|
||||
storage::Zalsa,
|
||||
AsDynDatabase as _, Database, Id, Revision,
|
||||
};
|
||||
|
||||
use super::{memo::Memo, Configuration, IngredientImpl};
|
||||
|
|
|
@ -2,7 +2,6 @@ use crossbeam::atomic::AtomicCell;
|
|||
|
||||
use crate::{
|
||||
local_state::{self, QueryOrigin, QueryRevisions},
|
||||
storage::ZalsaDatabase,
|
||||
tracked_struct::TrackedStructInDb,
|
||||
AsDynDatabase as _, Database, DatabaseKeyIndex, Id,
|
||||
};
|
||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -31,6 +31,8 @@ pub use self::cancelled::Cancelled;
|
|||
pub use self::cycle::Cycle;
|
||||
pub use self::database::AsDynDatabase;
|
||||
pub use self::database::Database;
|
||||
pub use self::database::DatabaseImpl;
|
||||
pub use self::database::UserData;
|
||||
pub use self::durability::Durability;
|
||||
pub use self::event::Event;
|
||||
pub use self::event::EventKind;
|
||||
|
@ -50,23 +52,9 @@ pub use salsa_macros::interned;
|
|||
pub use salsa_macros::tracked;
|
||||
pub use salsa_macros::Update;
|
||||
|
||||
pub fn default_database() -> impl Database {
|
||||
use crate as salsa;
|
||||
|
||||
#[crate::db]
|
||||
#[derive(Default)]
|
||||
struct DefaultDatabase {
|
||||
storage: Storage<Self>,
|
||||
}
|
||||
|
||||
#[crate::db]
|
||||
impl Database for DefaultDatabase {}
|
||||
|
||||
DefaultDatabase::default()
|
||||
}
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::Accumulator;
|
||||
pub use crate::Database;
|
||||
pub use crate::Setter;
|
||||
}
|
||||
|
||||
|
@ -82,6 +70,7 @@ pub mod plumbing {
|
|||
pub use crate::cycle::CycleRecoveryStrategy;
|
||||
pub use crate::database::current_revision;
|
||||
pub use crate::database::Database;
|
||||
pub use crate::database::UserData;
|
||||
pub use crate::function::should_backdate_value;
|
||||
pub use crate::id::AsId;
|
||||
pub use crate::id::FromId;
|
||||
|
@ -102,7 +91,6 @@ pub mod plumbing {
|
|||
pub use crate::storage::IngredientIndex;
|
||||
pub use crate::storage::Storage;
|
||||
pub use crate::storage::Zalsa;
|
||||
pub use crate::storage::ZalsaDatabase;
|
||||
pub use crate::tracked_struct::TrackedStructInDb;
|
||||
pub use crate::update::always_update;
|
||||
pub use crate::update::helper::Dispatch as UpdateDispatch;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use std::any::{Any, TypeId};
|
||||
use std::any::TypeId;
|
||||
|
||||
use orx_concurrent_vec::ConcurrentVec;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::cycle::CycleRecoveryStrategy;
|
||||
use crate::database::{DatabaseImpl, UserData};
|
||||
use crate::ingredient::{Ingredient, Jar};
|
||||
use crate::nonce::{Nonce, NonceGenerator};
|
||||
use crate::runtime::Runtime;
|
||||
|
@ -15,22 +16,6 @@ pub fn views<Db: ?Sized + Database>(db: &Db) -> &Views {
|
|||
db.zalsa().views()
|
||||
}
|
||||
|
||||
/// Salsa database methods whose implementation is generated by
|
||||
/// the `#[salsa::database]` procedural macro.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is meant to be implemented by our procedural macro.
|
||||
/// We need to document any non-obvious conditions that it satisfies.
|
||||
pub unsafe trait ZalsaDatabase: Any {
|
||||
/// Plumbing methods.
|
||||
#[doc(hidden)]
|
||||
fn zalsa(&self) -> &dyn Zalsa;
|
||||
|
||||
#[doc(hidden)]
|
||||
fn zalsa_mut(&mut self) -> &mut dyn Zalsa;
|
||||
}
|
||||
|
||||
/// The "plumbing interface" to the Salsa database.
|
||||
///
|
||||
/// **NOT SEMVER STABLE.**
|
||||
|
@ -87,9 +72,9 @@ pub trait Zalsa {
|
|||
fn report_tracked_write(&mut self, durability: Durability);
|
||||
}
|
||||
|
||||
impl<Db: Database> Zalsa for Storage<Db> {
|
||||
impl<U: UserData> Zalsa for Storage<U> {
|
||||
fn views(&self) -> &Views {
|
||||
&self.upcasts
|
||||
&self.views_of
|
||||
}
|
||||
|
||||
fn nonce(&self) -> Nonce<StorageNonce> {
|
||||
|
@ -227,8 +212,10 @@ impl IngredientIndex {
|
|||
|
||||
/// The "storage" struct stores all the data for the jars.
|
||||
/// It is shared between the main database and any active snapshots.
|
||||
pub struct Storage<Db: Database> {
|
||||
upcasts: ViewsOf<Db>,
|
||||
pub struct Storage<U: UserData> {
|
||||
user_data: U,
|
||||
|
||||
views_of: ViewsOf<DatabaseImpl<U>>,
|
||||
|
||||
nonce: Nonce<StorageNonce>,
|
||||
|
||||
|
@ -254,19 +241,30 @@ pub struct Storage<Db: Database> {
|
|||
}
|
||||
|
||||
// ANCHOR: default
|
||||
impl<Db: Database> Default for Storage<Db> {
|
||||
impl<U: UserData + Default> Default for Storage<U> {
|
||||
fn default() -> Self {
|
||||
Self::with(Default::default())
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: default
|
||||
|
||||
impl<U: UserData> Storage<U> {
|
||||
pub(crate) fn with(user_data: U) -> Self {
|
||||
Self {
|
||||
upcasts: Default::default(),
|
||||
views_of: Default::default(),
|
||||
nonce: NONCE.nonce(),
|
||||
jar_map: Default::default(),
|
||||
ingredients_vec: Default::default(),
|
||||
ingredients_requiring_reset: Default::default(),
|
||||
runtime: Runtime::default(),
|
||||
user_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn user_data(&self) -> &U {
|
||||
&self.user_data
|
||||
}
|
||||
}
|
||||
// ANCHOR_END: default
|
||||
|
||||
/// Caches a pointer to an ingredient in a database.
|
||||
/// Optimized for the case of a single database.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
mod common;
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Database};
|
||||
use salsa::{Accumulator, Database, DatabaseImpl};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::accumulator]
|
||||
|
@ -40,7 +40,7 @@ fn push_d_logs(db: &dyn Database) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_chain() {
|
||||
salsa::default_database().attach(|db| {
|
||||
DatabaseImpl::new().attach(|db| {
|
||||
let logs = push_logs::accumulated::<Log>(db);
|
||||
// Check that we get all the logs.
|
||||
expect![[r#"
|
||||
|
|
|
@ -27,7 +27,7 @@ fn push_logs(db: &dyn salsa::Database, input: MyInput) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_custom_clone() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, 2);
|
||||
let logs = push_logs::accumulated::<Log>(db, input);
|
||||
expect![[r##"
|
||||
|
|
|
@ -27,7 +27,7 @@ fn push_logs(db: &dyn salsa::Database, input: MyInput) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_custom_debug() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, 2);
|
||||
let logs = push_logs::accumulated::<Log>(db, input);
|
||||
expect![[r##"
|
||||
|
|
|
@ -39,7 +39,7 @@ fn push_b_logs(db: &dyn Database, input: MyInput) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_a_called_twice() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, 2, 3);
|
||||
let logs = push_logs::accumulated::<Log>(db, input);
|
||||
// Check that we don't see logs from `a` appearing twice in the input.
|
||||
|
|
|
@ -41,7 +41,7 @@ fn push_d_logs(db: &dyn Database) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_execution_order() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let logs = push_logs::accumulated::<Log>(db);
|
||||
// Check that we get logs in execution order
|
||||
expect![[r#"
|
||||
|
|
|
@ -2,16 +2,10 @@
|
|||
//! Then mutate the values so that the tracked function re-executes.
|
||||
//! Check that we accumulate the appropriate, new values.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct List {
|
||||
value: u32,
|
||||
|
@ -23,7 +17,7 @@ struct List {
|
|||
struct Integers(u32);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn compute(db: &dyn Db, input: List) {
|
||||
fn compute(db: &dyn salsa::Database, input: List) {
|
||||
eprintln!(
|
||||
"{:?}(value={:?}, next={:?})",
|
||||
input,
|
||||
|
@ -43,30 +37,9 @@ fn compute(db: &dyn Db, input: List) {
|
|||
eprintln!("pushed result {:?}", result);
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let l0 = List::new(&db, 1, None);
|
||||
let l1 = List::new(&db, 10, Some(l0));
|
||||
|
|
|
@ -73,7 +73,7 @@ fn push_e_logs(db: &dyn Database) {
|
|||
|
||||
#[test]
|
||||
fn accumulate_no_duplicates() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let logs = push_logs::accumulated::<Log>(db);
|
||||
// Test that there aren't duplicate B logs.
|
||||
// Note that log A appears twice, because they both come
|
||||
|
|
|
@ -3,15 +3,12 @@
|
|||
//! reuse.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use salsa::{Accumulator, DatabaseImpl, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct List {
|
||||
value: u32,
|
||||
|
@ -23,7 +20,7 @@ struct List {
|
|||
struct Integers(u32);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn compute(db: &dyn Db, input: List) -> u32 {
|
||||
fn compute(db: &dyn LogDatabase, input: List) -> u32 {
|
||||
db.push_log(format!("compute({:?})", input,));
|
||||
|
||||
// always pushes 0
|
||||
|
@ -42,38 +39,17 @@ fn compute(db: &dyn Db, input: List) -> u32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked(return_ref)]
|
||||
fn accumulated(db: &dyn Db, input: List) -> Vec<u32> {
|
||||
db.push_log(format!("accumulated({:?})", input,));
|
||||
fn accumulated(db: &dyn LogDatabase, input: List) -> Vec<u32> {
|
||||
db.push_log(format!("accumulated({:?})", input));
|
||||
compute::accumulated::<Integers>(db, input)
|
||||
.into_iter()
|
||||
.map(|a| a.0)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<Logger> = DatabaseImpl::default();
|
||||
|
||||
let l1 = List::new(&db, 1, None);
|
||||
let l2 = List::new(&db, 2, Some(l1));
|
||||
|
|
|
@ -4,15 +4,12 @@
|
|||
//! are the accumulated values from another query.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::prelude::*;
|
||||
use salsa::{prelude::*, DatabaseImpl};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct List {
|
||||
value: u32,
|
||||
|
@ -23,7 +20,7 @@ struct List {
|
|||
struct Integers(u32);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn compute(db: &dyn Db, input: List) -> u32 {
|
||||
fn compute(db: &dyn LogDatabase, input: List) -> u32 {
|
||||
db.push_log(format!("compute({:?})", input,));
|
||||
|
||||
// always pushes 0
|
||||
|
@ -41,30 +38,9 @@ fn compute(db: &dyn Db, input: List) -> u32 {
|
|||
result
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
let mut db = Database::default();
|
||||
let mut db = DatabaseImpl::with(Logger::default());
|
||||
|
||||
let l1 = List::new(&db, 1, None);
|
||||
let l2 = List::new(&db, 2, Some(l1));
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Accumulator, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field_a: u32,
|
||||
|
@ -18,7 +15,7 @@ struct MyInput {
|
|||
struct Log(#[allow(dead_code)] String);
|
||||
|
||||
#[salsa::tracked]
|
||||
fn push_logs(db: &dyn Db, input: MyInput) {
|
||||
fn push_logs(db: &dyn LogDatabase, input: MyInput) {
|
||||
db.push_log(format!(
|
||||
"push_logs(a = {}, b = {})",
|
||||
input.field_a(db),
|
||||
|
@ -37,7 +34,7 @@ fn push_logs(db: &dyn Db, input: MyInput) {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn push_a_logs(db: &dyn Db, input: MyInput) {
|
||||
fn push_a_logs(db: &dyn LogDatabase, input: MyInput) {
|
||||
let field_a = input.field_a(db);
|
||||
db.push_log(format!("push_a_logs({})", field_a));
|
||||
|
||||
|
@ -47,7 +44,7 @@ fn push_a_logs(db: &dyn Db, input: MyInput) {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn push_b_logs(db: &dyn Db, input: MyInput) {
|
||||
fn push_b_logs(db: &dyn LogDatabase, input: MyInput) {
|
||||
let field_a = input.field_b(db);
|
||||
db.push_log(format!("push_b_logs({})", field_a));
|
||||
|
||||
|
@ -56,30 +53,9 @@ fn push_b_logs(db: &dyn Db, input: MyInput) {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accumulate_once() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::with(Logger::default());
|
||||
|
||||
// Just call accumulate on a base input to see what happens.
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
|
@ -115,7 +91,7 @@ fn accumulate_once() {
|
|||
|
||||
#[test]
|
||||
fn change_a_from_2_to_0() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::with(Logger::default());
|
||||
|
||||
// Accumulate logs for `a = 2` and `b = 3`
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
|
@ -170,7 +146,7 @@ fn change_a_from_2_to_0() {
|
|||
|
||||
#[test]
|
||||
fn change_a_from_2_to_1() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::with(Logger::default());
|
||||
|
||||
// Accumulate logs for `a = 2` and `b = 3`
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
|
@ -229,7 +205,7 @@ fn change_a_from_2_to_1() {
|
|||
|
||||
#[test]
|
||||
fn get_a_logs_after_changing_b() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::with(Logger::default());
|
||||
|
||||
// Invoke `push_a_logs` with `a = 2` and `b = 3` (but `b` doesn't matter)
|
||||
let input = MyInput::new(&db, 2, 3);
|
||||
|
|
|
@ -2,16 +2,21 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use salsa::{DatabaseImpl, UserData};
|
||||
|
||||
/// Logging userdata: provides [`LogDatabase`][] trait.
|
||||
///
|
||||
/// If you wish to use it along with other userdata,
|
||||
/// you can also embed it in another struct and implement [`HasLogger`][] for that struct.
|
||||
#[derive(Default)]
|
||||
pub struct Logger {
|
||||
logs: std::sync::Mutex<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Trait implemented by databases that lets them log events.
|
||||
pub trait HasLogger {
|
||||
/// Return a reference to the logger from the database.
|
||||
fn logger(&self) -> &Logger;
|
||||
impl UserData for Logger {}
|
||||
|
||||
#[salsa::db]
|
||||
pub trait LogDatabase: HasLogger + salsa::Database {
|
||||
/// Log an event from inside a tracked function.
|
||||
fn push_log(&self, string: String) {
|
||||
self.logger().logs.lock().unwrap().push(string);
|
||||
|
@ -33,3 +38,86 @@ pub trait HasLogger {
|
|||
assert_eq!(logs.len(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl<U: HasLogger + UserData> LogDatabase for DatabaseImpl<U> {}
|
||||
|
||||
/// Trait implemented by databases that lets them log events.
|
||||
pub trait HasLogger {
|
||||
/// Return a reference to the logger from the database.
|
||||
fn logger(&self) -> &Logger;
|
||||
}
|
||||
|
||||
impl<U: HasLogger + UserData> HasLogger for DatabaseImpl<U> {
|
||||
fn logger(&self) -> &Logger {
|
||||
U::logger(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for Logger {
|
||||
fn logger(&self) -> &Logger {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Userdata that provides logging and logs salsa events.
|
||||
#[derive(Default)]
|
||||
pub struct EventLogger {
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
impl UserData for EventLogger {
|
||||
fn salsa_event(db: &DatabaseImpl<Self>, event: &dyn Fn() -> salsa::Event) {
|
||||
db.push_log(format!("{:?}", event()));
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for EventLogger {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DiscardLogger(Logger);
|
||||
|
||||
impl UserData for DiscardLogger {
|
||||
fn salsa_event(db: &DatabaseImpl<DiscardLogger>, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillDiscardStaleOutput { .. }
|
||||
| salsa::EventKind::DidDiscard { .. } => {
|
||||
db.push_log(format!("salsa_event({:?})", event.kind));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for DiscardLogger {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExecuteValidateLogger(Logger);
|
||||
|
||||
impl UserData for ExecuteValidateLogger {
|
||||
fn salsa_event(db: &DatabaseImpl<Self>, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillExecute { .. }
|
||||
| salsa::EventKind::DidValidateMemoizedValue { .. } => {
|
||||
db.push_log(format!("salsa_event({:?})", event.kind));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for ExecuteValidateLogger {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ mod a {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let mut db = salsa::default_database();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = a::MyInput::new(&mut db, 22);
|
||||
|
||||
input.field(&db);
|
||||
|
|
|
@ -16,7 +16,7 @@ fn tracked_fn<'db>(db: &'db dyn salsa::Database, input: MyInput) -> MyTracked<'d
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let mut db = salsa::default_database();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 22);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
input.set_field(&mut db).to(24);
|
||||
|
|
|
@ -4,7 +4,7 @@ pub struct MyInput {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let mut db = salsa::default_database();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&mut db, 22);
|
||||
input.field(&db);
|
||||
input.set_field(22);
|
||||
|
|
|
@ -10,6 +10,6 @@ fn my_fn(db: &dyn salsa::Database) {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let mut db = salsa::default_database();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
my_fn(&db);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ help: consider borrowing here
|
|||
warning: variable does not need to be mutable
|
||||
--> tests/compile-fail/span-tracked-getter.rs:13:9
|
||||
|
|
||||
13 | let mut db = salsa::default_database();
|
||||
13 | let mut db = salsa::DatabaseImpl::new();
|
||||
| ----^^
|
||||
| |
|
||||
| help: remove this `mut`
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::DatabaseImpl;
|
||||
use salsa::Durability;
|
||||
|
||||
// Axes:
|
||||
|
@ -59,17 +60,6 @@ struct Error {
|
|||
use salsa::Database as Db;
|
||||
use salsa::Setter;
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl RefUnwindSafe for Database {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {}
|
||||
|
||||
|
@ -169,7 +159,7 @@ fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle {
|
|||
|
||||
#[test]
|
||||
fn cycle_memoized() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db);
|
||||
let cycle = extract_cycle(|| memoized_a(db, input));
|
||||
let expected = expect![[r#"
|
||||
|
@ -184,7 +174,7 @@ fn cycle_memoized() {
|
|||
|
||||
#[test]
|
||||
fn cycle_volatile() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db);
|
||||
let cycle = extract_cycle(|| volatile_a(db, input));
|
||||
let expected = expect![[r#"
|
||||
|
@ -203,7 +193,7 @@ fn expect_cycle() {
|
|||
// ^ |
|
||||
// +-----+
|
||||
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(db, abc).is_err());
|
||||
})
|
||||
|
@ -214,7 +204,7 @@ fn inner_cycle() {
|
|||
// A --> B <-- C
|
||||
// ^ |
|
||||
// +-----+
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let abc = ABC::new(db, CycleQuery::B, CycleQuery::A, CycleQuery::B);
|
||||
let err = cycle_c(db, abc);
|
||||
assert!(err.is_err());
|
||||
|
@ -233,7 +223,7 @@ fn cycle_revalidate() {
|
|||
// A --> B
|
||||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
abc.set_b(&mut db).to(CycleQuery::A); // same value as default
|
||||
|
@ -245,7 +235,7 @@ fn cycle_recovery_unchanged_twice() {
|
|||
// A --> B
|
||||
// ^ |
|
||||
// +-----+
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::A, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_err());
|
||||
|
||||
|
@ -255,8 +245,7 @@ fn cycle_recovery_unchanged_twice() {
|
|||
|
||||
#[test]
|
||||
fn cycle_appears() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
// A --> B
|
||||
let abc = ABC::new(&db, CycleQuery::B, CycleQuery::None, CycleQuery::None);
|
||||
assert!(cycle_a(&db, abc).is_ok());
|
||||
|
@ -270,7 +259,7 @@ fn cycle_appears() {
|
|||
|
||||
#[test]
|
||||
fn cycle_disappears() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
// A --> B
|
||||
// ^ |
|
||||
|
@ -289,7 +278,7 @@ fn cycle_disappears() {
|
|||
/// the fact that the cycle will no longer occur.
|
||||
#[test]
|
||||
fn cycle_disappears_durability() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let abc = ABC::new(
|
||||
&mut db,
|
||||
CycleQuery::None,
|
||||
|
@ -320,7 +309,7 @@ fn cycle_disappears_durability() {
|
|||
|
||||
#[test]
|
||||
fn cycle_mixed_1() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
// A --> B <-- C
|
||||
// | ^
|
||||
// +-----+
|
||||
|
@ -338,7 +327,7 @@ fn cycle_mixed_1() {
|
|||
|
||||
#[test]
|
||||
fn cycle_mixed_2() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
// Configuration:
|
||||
//
|
||||
// A --> B --> C
|
||||
|
@ -360,7 +349,7 @@ fn cycle_mixed_2() {
|
|||
fn cycle_deterministic_order() {
|
||||
// No matter whether we start from A or B, we get the same set of participants:
|
||||
let f = || {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
// A --> B
|
||||
// ^ |
|
||||
|
@ -390,7 +379,7 @@ fn cycle_deterministic_order() {
|
|||
#[test]
|
||||
fn cycle_multiple() {
|
||||
// No matter whether we start from A or B, we get the same set of participants:
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
// Configuration:
|
||||
//
|
||||
|
@ -432,7 +421,7 @@ fn cycle_multiple() {
|
|||
|
||||
#[test]
|
||||
fn cycle_recovery_set_but_not_participating() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
// A --> C -+
|
||||
// ^ |
|
||||
// +--+
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Test that `DeriveWithDb` is correctly derived.
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Database as _, Setter};
|
||||
use salsa::{Database, Setter};
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -19,18 +19,9 @@ struct ComplexStruct {
|
|||
not_salsa: NotSalsa,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn input() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, 22);
|
||||
let not_salsa = NotSalsa {
|
||||
field: "it's salsa time".to_string(),
|
||||
|
@ -54,7 +45,7 @@ fn leak_debug_string(_db: &dyn salsa::Database, input: MyInput) -> String {
|
|||
/// Don't try this at home, kids.
|
||||
#[test]
|
||||
fn untracked_dependencies() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
|
||||
|
@ -95,7 +86,7 @@ fn leak_derived_custom(db: &dyn salsa::Database, input: MyInput, value: u32) ->
|
|||
|
||||
#[test]
|
||||
fn custom_debug_impl() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
|
||||
|
|
|
@ -3,22 +3,19 @@
|
|||
//! * when we delete memoized data, also delete outputs from that data
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{DiscardLogger, LogDatabase};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
use salsa::{DatabaseImpl, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input(singleton)]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result({:?})", input));
|
||||
let mut sum = 0;
|
||||
for tracked_struct in create_tracked_structs(db, input) {
|
||||
|
@ -33,7 +30,7 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn create_tracked_structs(db: &dyn Db, input: MyInput) -> Vec<MyTracked<'_>> {
|
||||
fn create_tracked_structs(db: &dyn LogDatabase, input: MyInput) -> Vec<MyTracked<'_>> {
|
||||
db.push_log(format!("intermediate_result({:?})", input));
|
||||
(0..input.field(db))
|
||||
.map(|i| MyTracked::new(db, i))
|
||||
|
@ -41,49 +38,19 @@ fn create_tracked_structs(db: &dyn Db, input: MyInput) -> Vec<MyTracked<'_>> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn contribution_from_struct<'db>(db: &'db dyn Db, tracked: MyTracked<'db>) -> u32 {
|
||||
fn contribution_from_struct<'db>(db: &'db dyn LogDatabase, tracked: MyTracked<'db>) -> u32 {
|
||||
let m = MyTracked::new(db, tracked.field(db));
|
||||
copy_field(db, m) * 2
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn copy_field<'db>(db: &'db dyn Db, tracked: MyTracked<'db>) -> u32 {
|
||||
fn copy_field<'db>(db: &'db dyn LogDatabase, tracked: MyTracked<'db>) -> u32 {
|
||||
tracked.field(db)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillDiscardStaleOutput { .. }
|
||||
| salsa::EventKind::DidDiscard { .. } => {
|
||||
self.push_log(format!("salsa_event({:?})", event.kind));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<DiscardLogger> = Default::default();
|
||||
|
||||
// Creates 3 tracked structs
|
||||
let input = MyInput::new(&db, 3);
|
||||
|
|
|
@ -56,7 +56,7 @@ impl MyInput {
|
|||
|
||||
#[test]
|
||||
fn deletion_drops() {
|
||||
let mut db = salsa::default_database();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
|
||||
|
|
|
@ -3,22 +3,19 @@
|
|||
//! * entities not created in a revision are deleted, as is any memoized data keyed on them.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::LogDatabase;
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result({:?})", input));
|
||||
let mut sum = 0;
|
||||
for tracked_struct in create_tracked_structs(db, input) {
|
||||
|
@ -33,7 +30,7 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn create_tracked_structs(db: &dyn Db, input: MyInput) -> Vec<MyTracked<'_>> {
|
||||
fn create_tracked_structs(db: &dyn LogDatabase, input: MyInput) -> Vec<MyTracked<'_>> {
|
||||
db.push_log(format!("intermediate_result({:?})", input));
|
||||
(0..input.field(db))
|
||||
.map(|i| MyTracked::new(db, i))
|
||||
|
@ -41,43 +38,13 @@ fn create_tracked_structs(db: &dyn Db, input: MyInput) -> Vec<MyTracked<'_>> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn contribution_from_struct<'db>(db: &'db dyn Db, tracked: MyTracked<'db>) -> u32 {
|
||||
fn contribution_from_struct<'db>(db: &'db dyn LogDatabase, tracked: MyTracked<'db>) -> u32 {
|
||||
tracked.field(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillDiscardStaleOutput { .. }
|
||||
| salsa::EventKind::DidDiscard { .. } => {
|
||||
self.push_log(format!("salsa_event({:?})", event.kind));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<common::DiscardLogger> = Default::default();
|
||||
|
||||
// Creates 3 tracked structs
|
||||
let input = MyInput::new(&db, 3);
|
||||
|
|
|
@ -2,22 +2,19 @@
|
|||
//! compiles and executes successfully.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
use salsa::{DatabaseImpl, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result({:?})", input));
|
||||
intermediate_result(db, input).field(db) * 2
|
||||
}
|
||||
|
@ -28,33 +25,14 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intermediate_result(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
||||
fn intermediate_result(db: &dyn LogDatabase, input: MyInput) -> MyTracked<'_> {
|
||||
db.push_log(format!("intermediate_result({:?})", input));
|
||||
MyTracked::new(db, input.field(db) / 2)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
|
|
@ -4,13 +4,10 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
use salsa::{DatabaseImpl, Setter};
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -18,13 +15,13 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result_depends_on_x(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result_depends_on_x(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result_depends_on_x({:?})", input));
|
||||
intermediate_result(db, input).x(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result_depends_on_y(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result_depends_on_y(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result_depends_on_y({:?})", input));
|
||||
intermediate_result(db, input).y(db) * 2
|
||||
}
|
||||
|
@ -36,36 +33,17 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intermediate_result(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
||||
fn intermediate_result(db: &dyn LogDatabase, input: MyInput) -> MyTracked<'_> {
|
||||
MyTracked::new(db, (input.field(db) + 1) / 2, input.field(db) / 2)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
// x = (input.field + 1) / 2
|
||||
// y = input.field / 2
|
||||
// final_result_depends_on_x = x * 2 = (input.field + 1) / 2 * 2
|
||||
// final_result_depends_on_y = y * 2 = input.field / 2 * 2
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
// intermediate results:
|
||||
// x = (22 + 1) / 2 = 11
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
x: u32,
|
||||
|
@ -19,41 +16,21 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn result_depends_on_x(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn result_depends_on_x(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("result_depends_on_x({:?})", input));
|
||||
input.x(db) + 1
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn result_depends_on_y(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn result_depends_on_y(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("result_depends_on_y({:?})", input));
|
||||
input.y(db) - 1
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
// result_depends_on_x = x + 1
|
||||
// result_depends_on_y = y - 1
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22, 33);
|
||||
assert_eq!(result_depends_on_x(&db, input), 23);
|
||||
|
|
|
@ -2,22 +2,19 @@
|
|||
//! compiles and executes successfully.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::Setter;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result({:?})", input));
|
||||
intermediate_result(db, input).field(db) * 2
|
||||
}
|
||||
|
@ -28,33 +25,14 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intermediate_result(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
||||
fn intermediate_result(db: &dyn LogDatabase, input: MyInput) -> MyTracked<'_> {
|
||||
db.push_log(format!("intermediate_result({:?})", input));
|
||||
MyTracked::new(db, input.field(db) / 2)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
@ -85,7 +63,7 @@ fn execute() {
|
|||
/// Create and mutate a distinct input. No re-execution required.
|
||||
#[test]
|
||||
fn red_herring() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
//! Test that a `tracked` fn on a `salsa::input`
|
||||
//! compiles and executes successfully.
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
|
||||
use expect_test::expect;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::interned]
|
||||
struct InternedString<'db> {
|
||||
data: String,
|
||||
|
@ -20,38 +15,17 @@ struct InternedPair<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intern_stuff(db: &dyn Db) -> String {
|
||||
fn intern_stuff(db: &dyn salsa::Database) -> String {
|
||||
let s1 = InternedString::new(db, "Hello, ".to_string());
|
||||
let s2 = InternedString::new(db, "World, ".to_string());
|
||||
let s3 = InternedPair::new(db, (s1, s2));
|
||||
format!("{s3:?}")
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
expect![[r#"
|
||||
"InternedPair { data: (InternedString { data: \"Hello, \" }, InternedString { data: \"World, \" }) }"
|
||||
"#]].assert_debug_eq(&intern_stuff(&db));
|
||||
db.assert_logs(expect!["[]"]);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,9 @@
|
|||
//! Test that a setting a field on a `#[salsa::input]`
|
||||
//! overwrites and returns the old value.
|
||||
|
||||
use salsa::Database;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database {}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: String,
|
||||
|
@ -34,7 +20,7 @@ struct MyInterned<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn test(db: &dyn crate::Db, input: MyInput) {
|
||||
fn test(db: &dyn Database, input: MyInput) {
|
||||
let input = is_send_sync(input);
|
||||
let interned = is_send_sync(MyInterned::new(db, input.field(db).clone()));
|
||||
let _tracked_struct = is_send_sync(MyTracked::new(db, interned));
|
||||
|
@ -46,7 +32,7 @@ fn is_send_sync<T: Send + Sync>(t: T) -> T {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, "Hello".to_string());
|
||||
test(&db, input);
|
||||
}
|
||||
|
|
40
tests/lru.rs
40
tests/lru.rs
|
@ -6,14 +6,11 @@ use std::sync::{
|
|||
Arc,
|
||||
};
|
||||
|
||||
use salsa::Database as _;
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
use salsa::Database as _;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct HotPotato(u32);
|
||||
|
||||
|
@ -40,50 +37,31 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked(lru = 32)]
|
||||
fn get_hot_potato(db: &dyn Db, input: MyInput) -> Arc<HotPotato> {
|
||||
fn get_hot_potato(db: &dyn LogDatabase, input: MyInput) -> Arc<HotPotato> {
|
||||
db.push_log(format!("get_hot_potato({:?})", input.field(db)));
|
||||
Arc::new(HotPotato::new(input.field(db)))
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn get_hot_potato2(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn get_hot_potato2(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("get_hot_potato2({:?})", input.field(db)));
|
||||
get_hot_potato(db, input).0
|
||||
}
|
||||
|
||||
#[salsa::tracked(lru = 32)]
|
||||
fn get_volatile(db: &dyn Db, _input: MyInput) -> usize {
|
||||
fn get_volatile(db: &dyn LogDatabase, _input: MyInput) -> usize {
|
||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
db.report_untracked_read();
|
||||
COUNTER.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct DatabaseImpl {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for DatabaseImpl {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for DatabaseImpl {}
|
||||
|
||||
impl HasLogger for DatabaseImpl {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
fn load_n_potatoes() -> usize {
|
||||
N_POTATOES.with(|n| n.load(Ordering::SeqCst))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lru_works() {
|
||||
let db = DatabaseImpl::default();
|
||||
let db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
assert_eq!(load_n_potatoes(), 0);
|
||||
|
||||
for i in 0..128u32 {
|
||||
|
@ -99,7 +77,7 @@ fn lru_works() {
|
|||
|
||||
#[test]
|
||||
fn lru_doesnt_break_volatile_queries() {
|
||||
let db = DatabaseImpl::default();
|
||||
let db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
// Create all inputs first, so that there are no revision changes among calls to `get_volatile`
|
||||
let inputs: Vec<MyInput> = (0..128usize).map(|i| MyInput::new(&db, i as u32)).collect();
|
||||
|
@ -117,7 +95,7 @@ fn lru_doesnt_break_volatile_queries() {
|
|||
|
||||
#[test]
|
||||
fn lru_can_be_changed_at_runtime() {
|
||||
let db = DatabaseImpl::default();
|
||||
let db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
assert_eq!(load_n_potatoes(), 0);
|
||||
|
||||
let inputs: Vec<(u32, MyInput)> = (0..128).map(|i| (i, MyInput::new(&db, i))).collect();
|
||||
|
@ -160,7 +138,7 @@ fn lru_can_be_changed_at_runtime() {
|
|||
|
||||
#[test]
|
||||
fn lru_keeps_dependency_info() {
|
||||
let mut db = DatabaseImpl::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
let capacity = 32;
|
||||
|
||||
// Invoke `get_hot_potato2` 33 times. This will (in turn) invoke
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
//! Test that a setting a field on a `#[salsa::input]`
|
||||
//! overwrites and returns the old value.
|
||||
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
|
||||
use salsa::Setter;
|
||||
use test_log::test;
|
||||
|
||||
|
@ -12,25 +9,9 @@ struct MyInput {
|
|||
field: String,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, "Hello".to_string());
|
||||
|
||||
|
|
|
@ -66,17 +66,5 @@ impl<'db> MyTracked<'db> {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
let mut db = Database::default();
|
||||
salsa::DatabaseImpl::new();
|
||||
}
|
||||
|
|
|
@ -6,20 +6,11 @@ struct MyTracked<'db> {
|
|||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "cannot create a tracked struct disambiguator outside of a tracked function"
|
||||
)]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
MyTracked::new(&db, 0);
|
||||
}
|
||||
|
|
|
@ -3,17 +3,12 @@
|
|||
//! both intra and cross thread.
|
||||
|
||||
use salsa::Cancelled;
|
||||
use salsa::DatabaseImpl;
|
||||
use salsa::Handle;
|
||||
use salsa::Setter;
|
||||
|
||||
use crate::setup::Database;
|
||||
use crate::setup::Knobs;
|
||||
|
||||
#[salsa::db]
|
||||
pub(crate) trait Db: salsa::Database + Knobs {}
|
||||
|
||||
#[salsa::db]
|
||||
impl<T: salsa::Database + Knobs> Db for T {}
|
||||
use crate::setup::KnobsDatabase;
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -21,14 +16,14 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn a1(db: &dyn Db, input: MyInput) -> MyInput {
|
||||
fn a1(db: &dyn KnobsDatabase, input: MyInput) -> MyInput {
|
||||
db.signal(1);
|
||||
db.wait_for(2);
|
||||
dummy(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn dummy(_db: &dyn Db, _input: MyInput) -> MyInput {
|
||||
fn dummy(_db: &dyn KnobsDatabase, _input: MyInput) -> MyInput {
|
||||
panic!("should never get here!")
|
||||
}
|
||||
|
||||
|
@ -49,7 +44,7 @@ fn dummy(_db: &dyn Db, _input: MyInput) -> MyInput {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Handle::new(Database::default());
|
||||
let mut db = Handle::new(<DatabaseImpl<Knobs>>::default());
|
||||
db.knobs().signal_on_will_block.store(3);
|
||||
|
||||
let input = MyInput::new(&*db, 1);
|
||||
|
|
|
@ -2,16 +2,11 @@
|
|||
//! See `../cycles.rs` for a complete listing of cycle tests,
|
||||
//! both intra and cross thread.
|
||||
|
||||
use salsa::DatabaseImpl;
|
||||
use salsa::Handle;
|
||||
|
||||
use crate::setup::Database;
|
||||
use crate::setup::Knobs;
|
||||
|
||||
#[salsa::db]
|
||||
pub(crate) trait Db: salsa::Database + Knobs {}
|
||||
|
||||
#[salsa::db]
|
||||
impl<T: salsa::Database + Knobs> Db for T {}
|
||||
use crate::setup::KnobsDatabase;
|
||||
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
|
@ -19,7 +14,7 @@ pub(crate) struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn = recover_a1)]
|
||||
pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.signal(1);
|
||||
db.wait_for(2);
|
||||
|
@ -27,23 +22,23 @@ pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
a2(db, input)
|
||||
}
|
||||
|
||||
fn recover_a1(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_a1(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_a1");
|
||||
key.field(db) * 10 + 1
|
||||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover_a2)]
|
||||
pub(crate) fn a2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
b1(db, input)
|
||||
}
|
||||
|
||||
fn recover_a2(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_a2(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_a2");
|
||||
key.field(db) * 10 + 2
|
||||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover_b1)]
|
||||
pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.wait_for(1);
|
||||
db.signal(2);
|
||||
|
@ -53,17 +48,17 @@ pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
b2(db, input)
|
||||
}
|
||||
|
||||
fn recover_b1(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_b1(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_b1");
|
||||
key.field(db) * 20 + 1
|
||||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover_b2)]
|
||||
pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
a1(db, input)
|
||||
}
|
||||
|
||||
fn recover_b2(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_b2(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_b2");
|
||||
key.field(db) * 20 + 2
|
||||
}
|
||||
|
@ -92,7 +87,7 @@ fn recover_b2(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Handle::new(Database::default());
|
||||
let db = Handle::new(<DatabaseImpl<Knobs>>::default());
|
||||
db.knobs().signal_on_will_block.store(3);
|
||||
|
||||
let input = MyInput::new(&*db, 1);
|
||||
|
|
|
@ -2,16 +2,9 @@
|
|||
//! See `../cycles.rs` for a complete listing of cycle tests,
|
||||
//! both intra and cross thread.
|
||||
|
||||
use salsa::Handle;
|
||||
use salsa::{DatabaseImpl, Handle};
|
||||
|
||||
use crate::setup::Database;
|
||||
use crate::setup::Knobs;
|
||||
|
||||
#[salsa::db]
|
||||
pub(crate) trait Db: salsa::Database + Knobs {}
|
||||
|
||||
#[salsa::db]
|
||||
impl<T: salsa::Database + Knobs> Db for T {}
|
||||
use crate::setup::{Knobs, KnobsDatabase};
|
||||
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
|
@ -19,7 +12,7 @@ pub(crate) struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// tell thread b we have started
|
||||
db.signal(1);
|
||||
|
||||
|
@ -30,25 +23,25 @@ pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// create the cycle
|
||||
b1(db, input)
|
||||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover_b1)]
|
||||
pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// wait for thread a to have started
|
||||
db.wait_for(1);
|
||||
b2(db, input)
|
||||
}
|
||||
|
||||
fn recover_b1(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_b1(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_b1");
|
||||
key.field(db) * 20 + 2
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// will encounter a cycle but recover
|
||||
b3(db, input);
|
||||
b1(db, input); // hasn't recovered yet
|
||||
|
@ -56,12 +49,12 @@ pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover_b3)]
|
||||
pub(crate) fn b3(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b3(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// will block on thread a, signaling stage 2
|
||||
a1(db, input)
|
||||
}
|
||||
|
||||
fn recover_b3(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover_b3(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover_b3");
|
||||
key.field(db) * 200 + 2
|
||||
}
|
||||
|
@ -88,7 +81,7 @@ fn recover_b3(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Handle::new(Database::default());
|
||||
let db = Handle::new(<DatabaseImpl<Knobs>>::default());
|
||||
db.knobs().signal_on_will_block.store(3);
|
||||
|
||||
let input = MyInput::new(&*db, 1);
|
||||
|
|
|
@ -2,25 +2,20 @@
|
|||
//! See the `../cycles.rs` for a complete listing of cycle tests,
|
||||
//! both intra and cross thread.
|
||||
|
||||
use crate::setup::Database;
|
||||
use crate::setup::Knobs;
|
||||
use crate::setup::KnobsDatabase;
|
||||
use expect_test::expect;
|
||||
use salsa::Database as _;
|
||||
use salsa::DatabaseImpl;
|
||||
use salsa::Handle;
|
||||
|
||||
#[salsa::db]
|
||||
pub(crate) trait Db: salsa::Database + Knobs {}
|
||||
|
||||
#[salsa::db]
|
||||
impl<T: salsa::Database + Knobs> Db for T {}
|
||||
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.signal(1);
|
||||
db.wait_for(2);
|
||||
|
@ -29,7 +24,7 @@ pub(crate) fn a(db: &dyn Db, input: MyInput) -> i32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.wait_for(1);
|
||||
db.signal(2);
|
||||
|
@ -43,7 +38,7 @@ pub(crate) fn b(db: &dyn Db, input: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Handle::new(Database::default());
|
||||
let db = Handle::new(<DatabaseImpl<Knobs>>::default());
|
||||
db.knobs().signal_on_will_block.store(3);
|
||||
|
||||
let input = MyInput::new(&*db, -1);
|
||||
|
|
|
@ -2,16 +2,9 @@
|
|||
//! See `../cycles.rs` for a complete listing of cycle tests,
|
||||
//! both intra and cross thread.
|
||||
|
||||
use salsa::Handle;
|
||||
use salsa::{DatabaseImpl, Handle};
|
||||
|
||||
use crate::setup::Database;
|
||||
use crate::setup::Knobs;
|
||||
|
||||
#[salsa::db]
|
||||
pub(crate) trait Db: salsa::Database + Knobs {}
|
||||
|
||||
#[salsa::db]
|
||||
impl<T: salsa::Database + Knobs> Db for T {}
|
||||
use crate::setup::{Knobs, KnobsDatabase};
|
||||
|
||||
#[salsa::input]
|
||||
pub(crate) struct MyInput {
|
||||
|
@ -19,7 +12,7 @@ pub(crate) struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.signal(1);
|
||||
db.wait_for(2);
|
||||
|
@ -28,17 +21,17 @@ pub(crate) fn a1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked(recovery_fn=recover)]
|
||||
pub(crate) fn a2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn a2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
b1(db, input)
|
||||
}
|
||||
|
||||
fn recover(db: &dyn Db, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
fn recover(db: &dyn KnobsDatabase, _cycle: &salsa::Cycle, key: MyInput) -> i32 {
|
||||
dbg!("recover");
|
||||
key.field(db) * 20 + 2
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b1(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
// Wait to create the cycle until both threads have entered
|
||||
db.wait_for(1);
|
||||
db.signal(2);
|
||||
|
@ -49,7 +42,7 @@ pub(crate) fn b1(db: &dyn Db, input: MyInput) -> i32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
||||
pub(crate) fn b2(db: &dyn KnobsDatabase, input: MyInput) -> i32 {
|
||||
a1(db, input)
|
||||
}
|
||||
|
||||
|
@ -77,7 +70,7 @@ pub(crate) fn b2(db: &dyn Db, input: MyInput) -> i32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Handle::new(Database::default());
|
||||
let db = Handle::new(<DatabaseImpl<Knobs>>::default());
|
||||
db.knobs().signal_on_will_block.store(3);
|
||||
|
||||
let input = MyInput::new(&*db, 1);
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use crossbeam::atomic::AtomicCell;
|
||||
use salsa::{Database, DatabaseImpl, UserData};
|
||||
|
||||
use crate::signal::Signal;
|
||||
|
||||
/// Various "knobs" and utilities used by tests to force
|
||||
/// a certain behavior.
|
||||
pub(crate) trait Knobs {
|
||||
fn knobs(&self) -> &KnobsStruct;
|
||||
#[salsa::db]
|
||||
pub(crate) trait KnobsDatabase: Database {
|
||||
fn knobs(&self) -> &Knobs;
|
||||
|
||||
fn signal(&self, stage: usize);
|
||||
|
||||
|
@ -16,7 +18,7 @@ pub(crate) trait Knobs {
|
|||
/// behave on one specific thread. Note that this state is
|
||||
/// intentionally thread-local (apart from `signal`).
|
||||
#[derive(Default)]
|
||||
pub(crate) struct KnobsStruct {
|
||||
pub(crate) struct Knobs {
|
||||
/// A kind of flexible barrier used to coordinate execution across
|
||||
/// threads to ensure we reach various weird states.
|
||||
pub(crate) signal: Signal,
|
||||
|
@ -28,39 +30,32 @@ pub(crate) struct KnobsStruct {
|
|||
pub(crate) signal_on_did_cancel: AtomicCell<usize>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
knobs: KnobsStruct,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
impl UserData for Knobs {
|
||||
fn salsa_event(db: &DatabaseImpl<Self>, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillBlockOn { .. } => {
|
||||
self.signal(self.knobs().signal_on_will_block.load());
|
||||
db.signal(db.signal_on_will_block.load());
|
||||
}
|
||||
salsa::EventKind::DidSetCancellationFlag => {
|
||||
self.signal(self.knobs().signal_on_did_cancel.load());
|
||||
db.signal(db.signal_on_did_cancel.load());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Knobs for Database {
|
||||
fn knobs(&self) -> &KnobsStruct {
|
||||
&self.knobs
|
||||
#[salsa::db]
|
||||
impl KnobsDatabase for DatabaseImpl<Knobs> {
|
||||
fn knobs(&self) -> &Knobs {
|
||||
self
|
||||
}
|
||||
|
||||
fn signal(&self, stage: usize) {
|
||||
self.knobs.signal.signal(stage);
|
||||
self.signal.signal(stage);
|
||||
}
|
||||
|
||||
fn wait_for(&self, stage: usize) {
|
||||
self.knobs.signal.wait_for(stage);
|
||||
self.signal.wait_for(stage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,41 +5,14 @@ use std::cell::Cell;
|
|||
|
||||
use expect_test::expect;
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use salsa::Setter;
|
||||
use common::{EventLogger, LogDatabase};
|
||||
use salsa::{Database, Setter};
|
||||
use test_log::test;
|
||||
|
||||
thread_local! {
|
||||
static COUNTER: Cell<usize> = const { Cell::new(0) };
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
self.push_log(format!("{event:?}"));
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field1: u32,
|
||||
|
@ -52,7 +25,7 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn function(db: &dyn Db, input: MyInput) -> usize {
|
||||
fn function(db: &dyn Database, input: MyInput) -> usize {
|
||||
// Read input 1
|
||||
let _field1 = input.field1(db);
|
||||
|
||||
|
@ -71,7 +44,7 @@ fn function(db: &dyn Db, input: MyInput) -> usize {
|
|||
|
||||
#[test]
|
||||
fn test_leaked_inputs_ignored() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<EventLogger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 10, 20);
|
||||
let result_in_rev_1 = function(&db, input);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
//! Singleton structs are created only once. Subsequent `get`s and `new`s after creation return the same `Id`.
|
||||
|
||||
use expect_test::expect;
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
|
||||
use salsa::Database as _;
|
||||
use test_log::test;
|
||||
|
@ -15,25 +13,9 @@ struct MyInput {
|
|||
id_field: u16,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
let input1 = MyInput::new(&db, 3, 4);
|
||||
let input2 = MyInput::get(&db);
|
||||
|
||||
|
@ -46,7 +28,7 @@ fn basic() {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn twice() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
let input1 = MyInput::new(&db, 3, 4);
|
||||
let input2 = MyInput::get(&db);
|
||||
|
||||
|
@ -58,7 +40,7 @@ fn twice() {
|
|||
|
||||
#[test]
|
||||
fn debug() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, 3, 4);
|
||||
let actual = format!("{:?}", input);
|
||||
let expected = expect!["MyInput { [salsa id]: Id(0), field: 3, id_field: 4 }"];
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
//! compilation succeeds but execution panics
|
||||
#![allow(warnings)]
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
|
@ -16,12 +13,15 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn tracked_struct_created_in_another_query<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
fn tracked_struct_created_in_another_query<'db>(
|
||||
db: &'db dyn salsa::Database,
|
||||
input: MyInput,
|
||||
) -> MyTracked<'db> {
|
||||
MyTracked::new(db, input.field(db) * 2)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
||||
fn tracked_fn<'db>(db: &'db dyn salsa::Database, input: MyInput) -> MyTracked<'db> {
|
||||
let t = tracked_struct_created_in_another_query(db, input);
|
||||
if input.field(db) != 0 {
|
||||
tracked_fn_extra::specify(db, t, 2222);
|
||||
|
@ -30,28 +30,16 @@ fn tracked_fn<'db>(db: &'db dyn Db, input: MyInput) -> MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked(specify)]
|
||||
fn tracked_fn_extra<'db>(_db: &'db dyn Db, _input: MyTracked<'db>) -> u32 {
|
||||
fn tracked_fn_extra<'db>(_db: &'db dyn salsa::Database, _input: MyTracked<'db>) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "can only use `specify` on salsa structs created during the current tracked fn"
|
||||
)]
|
||||
fn execute_when_specified() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 22);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
|
||||
mod common;
|
||||
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{ExecuteValidateLogger, LogDatabase, Logger};
|
||||
use expect_test::expect;
|
||||
use salsa::{Database as _, Durability, Event, EventKind};
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
use salsa::{Database, DatabaseImpl, Durability, Event, EventKind};
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -17,47 +14,20 @@ struct MyInput {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn tracked_fn(db: &dyn Database, input: MyInput) -> u32 {
|
||||
input.field(db) * 2
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: Event) {
|
||||
if let EventKind::WillExecute { .. } | EventKind::DidValidateMemoizedValue { .. } =
|
||||
event.kind
|
||||
{
|
||||
self.push_log(format!("{:?}", event.kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<ExecuteValidateLogger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input), 44);
|
||||
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
"WillExecute { database_key: tracked_fn(0) }",
|
||||
"salsa_event(WillExecute { database_key: tracked_fn(0) })",
|
||||
]"#]]);
|
||||
|
||||
// Bumps the revision
|
||||
|
@ -68,6 +38,6 @@ fn execute() {
|
|||
|
||||
db.assert_logs(expect![[r#"
|
||||
[
|
||||
"DidValidateMemoizedValue { database_key: tracked_fn(0) }",
|
||||
"salsa_event(DidValidateMemoizedValue { database_key: tracked_fn(0) })",
|
||||
]"#]]);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Test an id field whose `PartialEq` impl is always true.
|
||||
|
||||
use salsa::{Database as Db, Setter};
|
||||
use salsa::{Database, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::input]
|
||||
|
@ -33,24 +33,14 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn the_fn(db: &dyn Db, input: MyInput) {
|
||||
fn the_fn(db: &dyn Database, input: MyInput) {
|
||||
let tracked0 = MyTracked::new(db, BadEq::from(input.field(db)));
|
||||
assert_eq!(tracked0.field(db).field, input.field(db));
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, true);
|
||||
the_fn(&db, input);
|
||||
input.set_field(&mut db).to(false);
|
||||
|
|
|
@ -42,18 +42,9 @@ fn the_fn(db: &dyn Db, input: MyInput) {
|
|||
assert_eq!(tracked0.field(db).field, input.field(db));
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, true);
|
||||
the_fn(&db, input);
|
||||
|
|
|
@ -16,18 +16,9 @@ fn tracked_fn(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
|||
MyTracked::new(db, input.field(db) / 2)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input1 = MyInput::new(&db, 22);
|
||||
let input2 = MyInput::new(&db, 44);
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
//! if we were to execute from scratch.
|
||||
|
||||
use expect_test::expect;
|
||||
use salsa::{Database as Db, Setter};
|
||||
use salsa::{Database, Setter};
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::LogDatabase;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::input]
|
||||
|
@ -37,51 +37,24 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn the_fn(db: &dyn Db, input: MyInput) -> bool {
|
||||
fn the_fn(db: &dyn Database, input: MyInput) -> bool {
|
||||
let tracked = make_tracked_struct(db, input);
|
||||
read_tracked_struct(db, tracked)
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn make_tracked_struct(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
||||
fn make_tracked_struct(db: &dyn Database, input: MyInput) -> MyTracked<'_> {
|
||||
MyTracked::new(db, BadEq::from(input.field(db)))
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn read_tracked_struct<'db>(db: &'db dyn Db, tracked: MyTracked<'db>) -> bool {
|
||||
fn read_tracked_struct<'db>(db: &'db dyn Database, tracked: MyTracked<'db>) -> bool {
|
||||
tracked.field(db).field
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {
|
||||
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
|
||||
let event = event();
|
||||
match event.kind {
|
||||
salsa::EventKind::WillExecute { .. }
|
||||
| salsa::EventKind::DidValidateMemoizedValue { .. } => {
|
||||
self.push_log(format!("salsa_event({:?})", event.kind));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<common::ExecuteValidateLogger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, true);
|
||||
let result = the_fn(&db, input);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//! This can our "last changed" data to be wrong
|
||||
//! but we *should* always reflect the final values.
|
||||
|
||||
use salsa::{Database as Db, Setter};
|
||||
use salsa::{Database, Setter};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::input]
|
||||
|
@ -28,23 +28,14 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn the_fn(db: &dyn Db, input: MyInput) {
|
||||
fn the_fn(db: &dyn Database, input: MyInput) {
|
||||
let tracked0 = MyTracked::new(db, NotEq::from(input.field(db)));
|
||||
assert_eq!(tracked0.field(db).field, input.field(db));
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
|
||||
let input = MyInput::new(&db, true);
|
||||
the_fn(&db, input);
|
||||
|
|
|
@ -9,15 +9,6 @@ fn tracked_fn(db: &dyn salsa::Database) -> u32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
assert_eq!(tracked_fn(&db), 44);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
mod common;
|
||||
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
use expect_test::expect;
|
||||
use salsa::Setter as _;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
use salsa::{DatabaseImpl, Setter as _};
|
||||
|
||||
#[salsa::input]
|
||||
struct Input {
|
||||
|
@ -13,7 +10,7 @@ struct Input {
|
|||
}
|
||||
|
||||
#[salsa::tracked(no_eq)]
|
||||
fn abs_float(db: &dyn Db, input: Input) -> f32 {
|
||||
fn abs_float(db: &dyn LogDatabase, input: Input) -> f32 {
|
||||
let number = input.number(db);
|
||||
|
||||
db.push_log(format!("abs_float({number})"));
|
||||
|
@ -21,35 +18,15 @@ fn abs_float(db: &dyn Db, input: Input) -> f32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn derived(db: &dyn Db, input: Input) -> u32 {
|
||||
fn derived(db: &dyn LogDatabase, input: Input) -> u32 {
|
||||
let x = abs_float(db, input);
|
||||
db.push_log("derived".to_string());
|
||||
|
||||
x as u32
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
#[test]
|
||||
fn invoke() {
|
||||
let mut db = Database::default();
|
||||
let mut db: DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = Input::new(&db, 5);
|
||||
let x = derived(&db, input);
|
||||
|
|
|
@ -14,16 +14,7 @@ fn tracked_fn(db: &dyn salsa::Database, input: MyInput) -> u32 {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input), 44);
|
||||
}
|
||||
|
|
|
@ -11,18 +11,9 @@ fn tracked_fn<'db>(db: &'db dyn salsa::Database, name: Name<'db>) -> String {
|
|||
name.name(db).clone()
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
let name = Name::new(&db, "Salsa".to_string());
|
||||
|
||||
assert_eq!(tracked_fn(&db, name), "Salsa");
|
||||
|
|
|
@ -16,18 +16,9 @@ fn tracked_fn(db: &dyn salsa::Database, input: MyInput) -> MyTracked<'_> {
|
|||
MyTracked::new(db, input.field(db) * 2)
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let db = Database::default();
|
||||
let db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input).field(&db), 44);
|
||||
}
|
||||
|
|
|
@ -26,18 +26,9 @@ fn tracked_fn_extra<'db>(_db: &'db dyn salsa::Database, _input: MyTracked<'db>)
|
|||
0
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn execute_when_specified() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 22);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
assert_eq!(tracked.field(&db), 44);
|
||||
|
@ -46,7 +37,7 @@ fn execute_when_specified() {
|
|||
|
||||
#[test]
|
||||
fn execute_when_not_specified() {
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let input = MyInput::new(&db, 0);
|
||||
let tracked = tracked_fn(&db, input);
|
||||
assert_eq!(tracked.field(&db), 0);
|
||||
|
|
|
@ -3,20 +3,17 @@
|
|||
|
||||
use expect_test::expect;
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
use common::{LogDatabase, Logger};
|
||||
use salsa::Setter;
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn final_result(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn final_result(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("final_result({:?})", input));
|
||||
intermediate_result(db, input).field(db) * 2
|
||||
}
|
||||
|
@ -27,35 +24,16 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn intermediate_result(db: &dyn Db, input: MyInput) -> MyTracked<'_> {
|
||||
fn intermediate_result(db: &dyn LogDatabase, input: MyInput) -> MyTracked<'_> {
|
||||
db.push_log(format!("intermediate_result({:?})", input));
|
||||
let tracked = MyTracked::new(db, input.field(db) / 2);
|
||||
let _ = tracked.field(db); // read the field of an entity we created
|
||||
tracked
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_entity() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
@ -86,7 +64,7 @@ fn one_entity() {
|
|||
/// Create and mutate a distinct input. No re-execution required.
|
||||
#[test]
|
||||
fn red_herring() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = Default::default();
|
||||
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(final_result(&db, input), 22);
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use expect_test::expect;
|
||||
use salsa::Database as SalsaDatabase;
|
||||
mod common;
|
||||
use common::{HasLogger, Logger};
|
||||
|
||||
#[salsa::db]
|
||||
trait Db: salsa::Database + HasLogger {}
|
||||
use common::{LogDatabase, Logger};
|
||||
use salsa::Database;
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
|
@ -17,7 +14,7 @@ struct MyTracked<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn tracked_fn(db: &dyn Db, input: MyInput) -> u32 {
|
||||
fn tracked_fn(db: &dyn LogDatabase, input: MyInput) -> u32 {
|
||||
db.push_log(format!("tracked_fn({input:?})"));
|
||||
let t = MyTracked::new(db, input.field(db) * 2);
|
||||
tracked_fn_extra::specify(db, t, 2222);
|
||||
|
@ -25,33 +22,14 @@ fn tracked_fn(db: &dyn Db, input: MyInput) -> u32 {
|
|||
}
|
||||
|
||||
#[salsa::tracked(specify)]
|
||||
fn tracked_fn_extra<'db>(db: &dyn Db, input: MyTracked<'db>) -> u32 {
|
||||
fn tracked_fn_extra<'db>(db: &dyn LogDatabase, input: MyTracked<'db>) -> u32 {
|
||||
db.push_log(format!("tracked_fn_extra({input:?})"));
|
||||
0
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
logger: Logger,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::db]
|
||||
impl Db for Database {}
|
||||
|
||||
impl HasLogger for Database {
|
||||
fn logger(&self) -> &Logger {
|
||||
&self.logger
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute() {
|
||||
let mut db = Database::default();
|
||||
let mut db: salsa::DatabaseImpl<Logger> = salsa::DatabaseImpl::default();
|
||||
let input = MyInput::new(&db, 22);
|
||||
assert_eq!(tracked_fn(&db, input), 2222);
|
||||
db.assert_logs(expect![[r#"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use salsa::Database as _;
|
||||
use salsa::Database;
|
||||
|
||||
#[salsa::input]
|
||||
struct Input {
|
||||
|
@ -12,18 +12,9 @@ fn test(db: &dyn salsa::Database, input: Input) -> Vec<String> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn invoke() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = Input::new(db, 3);
|
||||
let x: &Vec<String> = test(db, input);
|
||||
expect_test::expect![[r#"
|
||||
|
|
|
@ -34,16 +34,7 @@ impl TrackedTrait for MyInput {
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
let mut db = Database::default();
|
||||
let mut db = salsa::DatabaseImpl::new();
|
||||
let object = MyInput::new(&mut db, 22);
|
||||
// assert_eq!(object.tracked_fn(&db), 44);
|
||||
// assert_eq!(*object.tracked_fn_ref(&db), 66);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use salsa::Database as _;
|
||||
use salsa::Database;
|
||||
|
||||
#[salsa::input]
|
||||
struct Input {
|
||||
|
@ -15,18 +15,9 @@ impl Input {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn invoke() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = Input::new(db, 3);
|
||||
let x: &Vec<String> = input.test(db);
|
||||
expect_test::expect![[r#"
|
||||
|
|
|
@ -43,7 +43,7 @@ impl<'db1> ItemName<'db1> for SourceTree<'db1> {
|
|||
|
||||
#[test]
|
||||
fn test_inherent() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = Input::new(db, "foo".to_string());
|
||||
let source_tree = input.source_tree(db);
|
||||
expect_test::expect![[r#"
|
||||
|
@ -55,7 +55,7 @@ fn test_inherent() {
|
|||
|
||||
#[test]
|
||||
fn test_trait() {
|
||||
salsa::default_database().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = Input::new(db, "foo".to_string());
|
||||
let source_tree = input.source_tree(db);
|
||||
expect_test::expect![[r#"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use salsa::Database as _;
|
||||
use salsa::Database;
|
||||
|
||||
#[salsa::input]
|
||||
struct Input {
|
||||
|
@ -19,18 +19,9 @@ impl Trait for Input {
|
|||
}
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn invoke() {
|
||||
Database::default().attach(|db| {
|
||||
salsa::DatabaseImpl::new().attach(|db| {
|
||||
let input = Input::new(db, 3);
|
||||
let x: &Vec<String> = input.test(db);
|
||||
expect_test::expect![[r#"
|
||||
|
|
|
@ -20,14 +20,5 @@ struct MyTracked2<'db2> {
|
|||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[test]
|
||||
fn create_db() {}
|
||||
|
|
|
@ -3,15 +3,6 @@
|
|||
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: String,
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
//! Test that a setting a field on a `#[salsa::input]`
|
||||
//! overwrites and returns the old value.
|
||||
|
||||
use salsa::Database as _;
|
||||
use salsa::{Database, DatabaseImpl};
|
||||
use test_log::test;
|
||||
|
||||
#[salsa::db]
|
||||
#[derive(Default)]
|
||||
struct Database {
|
||||
storage: salsa::Storage<Self>,
|
||||
}
|
||||
|
||||
#[salsa::db]
|
||||
impl salsa::Database for Database {}
|
||||
|
||||
#[salsa::input]
|
||||
struct MyInput {
|
||||
field: String,
|
||||
|
@ -31,7 +22,7 @@ enum MyList<'db> {
|
|||
}
|
||||
|
||||
#[salsa::tracked]
|
||||
fn create_tracked_list(db: &dyn salsa::Database, input: MyInput) -> MyTracked<'_> {
|
||||
fn create_tracked_list(db: &dyn Database, input: MyInput) -> MyTracked<'_> {
|
||||
let t0 = MyTracked::new(db, input, MyList::None);
|
||||
let t1 = MyTracked::new(db, input, MyList::Next(t0));
|
||||
t1
|
||||
|
@ -39,7 +30,7 @@ fn create_tracked_list(db: &dyn salsa::Database, input: MyInput) -> MyTracked<'_
|
|||
|
||||
#[test]
|
||||
fn execute() {
|
||||
Database::default().attach(|db| {
|
||||
DatabaseImpl::new().attach(|db| {
|
||||
let input = MyInput::new(db, "foo".to_string());
|
||||
let t0: MyTracked = create_tracked_list(db, input);
|
||||
let t1 = create_tracked_list(db, input);
|
||||
|
|
Loading…
Reference in a new issue