Defining the database struct
First, we need to create the database struct. Typically it is only used by the "driver" of your application; the one which starts up the program, supplies the inputs, and relays the outputs.
In calc
, the database struct is in the db
module, and it looks like this:
#![allow(unused)] fn main() { #[salsa::db] #[derive(Clone)] #[cfg_attr(not(test), derive(Default))] pub struct CalcDatabaseImpl { storage: salsa::Storage<Self>, // The logs are only used for testing and demonstrating reuse: #[cfg(test)] logs: Arc<Mutex<Option<Vec<String>>>>, } #[cfg(test)] impl Default for CalcDatabaseImpl { fn default() -> Self { let logs = <Arc<Mutex<Option<Vec<String>>>>>::default(); Self { storage: salsa::Storage::new(Some(Box::new({ let logs = logs.clone(); move |event| { eprintln!("Event: {event:?}"); // Log interesting events, if logging is enabled if let Some(logs) = &mut *logs.lock().unwrap() { // only log interesting events if let salsa::EventKind::WillExecute { .. } = event.kind { logs.push(format!("Event: {event:?}")); } } } }))), logs, } } } }
The #[salsa::db]
attribute marks the struct as a database.
It must have a field named storage
whose type is salsa::Storage<Self>
, but it can also contain whatever other fields you want.
Implementing the salsa::Database
trait
In addition to the struct itself, we must add an impl of salsa::Database
:
#![allow(unused)] fn main() { #[salsa::db] impl salsa::Database for CalcDatabaseImpl {} }
Implementing the salsa::ParallelDatabase
trait
If you want to permit accessing your database from multiple threads at once, then you also need to implement the ParallelDatabase
trait:
#![allow(unused)] fn main() { }