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() {
}