2018-10-02 09:50:38 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-10-05 15:03:51 +00:00
|
|
|
// Step 1. Define the query group
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2018-10-05 15:03:51 +00:00
|
|
|
// A **query group** is a collection of queries (both inputs and
|
2019-01-25 15:25:17 +00:00
|
|
|
// functions) that are defined in one particular spot. Each query
|
|
|
|
// group is defined by a representative struct (used internally by
|
|
|
|
// Salsa) as well as a representative trait. By convention, for a
|
|
|
|
// query group `Foo`, the struct is named `Foo` and the trait is named
|
|
|
|
// `FooDatabase`. The name `FooDatabase` reflects the fact that the
|
|
|
|
// trait is implemented by **the database**, which stores all the data
|
|
|
|
// in the system. Each query group thus represents a subset of the
|
|
|
|
// full data.
|
|
|
|
//
|
|
|
|
// To define a query group, you annotate a trait definition with the
|
|
|
|
// `#[salsa::query_group(Foo)]` attribute macro. In addition to the
|
|
|
|
// trait definition, the macro will generate a struct with the name
|
|
|
|
// `Foo` that you provide, as well as various other bits of glue.
|
|
|
|
//
|
|
|
|
// Note that one query group can "include" another by listing the
|
|
|
|
// trait for that query group as a supertrait.
|
|
|
|
#[salsa::query_group(HelloWorld)]
|
2019-01-12 10:11:59 +00:00
|
|
|
trait HelloWorldDatabase: salsa::Database {
|
2019-01-25 10:16:57 +00:00
|
|
|
// For each query, we give the name, some input keys (here, we
|
|
|
|
// have one key, `()`) and the output type `Arc<String>`. We can
|
|
|
|
// use attributes to give other configuration:
|
2019-01-12 10:11:59 +00:00
|
|
|
//
|
|
|
|
// - `salsa::input` indicates that this is an "input" to the system,
|
2019-01-25 10:16:57 +00:00
|
|
|
// which must be explicitly set. The `salsa::query_group` method
|
|
|
|
// will autogenerate a `set_input_string` method that can be
|
|
|
|
// used to set the input.
|
2019-01-12 10:11:59 +00:00
|
|
|
#[salsa::input]
|
|
|
|
fn input_string(&self, key: ()) -> Arc<String>;
|
|
|
|
|
|
|
|
// This is a *derived query*, meaning its value is specified by
|
|
|
|
// a function (see Step 2, below).
|
|
|
|
fn length(&self, key: ()) -> usize;
|
2018-10-02 09:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Step 2. Define the queries.
|
|
|
|
|
2018-10-05 15:03:51 +00:00
|
|
|
// Define the **function** for the `length` query. This function will
|
|
|
|
// be called whenever the query's value must be recomputed. After it
|
|
|
|
// is called once, its result is typically memoized, unless we think
|
|
|
|
// that one of the inputs may have changed. Its first argument (`db`)
|
|
|
|
// is the "database", which is the type that contains the storage for
|
|
|
|
// all of the queries in the system -- we never know the concrete type
|
|
|
|
// here, we only know the subset of methods we care about (defined by
|
|
|
|
// the `HelloWorldDatabase` trait we specified above).
|
2018-10-05 14:30:17 +00:00
|
|
|
fn length(db: &impl HelloWorldDatabase, (): ()) -> usize {
|
|
|
|
// Read the input string:
|
|
|
|
let input_string = db.input_string(());
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2018-10-05 14:30:17 +00:00
|
|
|
// Return its length:
|
|
|
|
input_string.len()
|
2018-10-02 09:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-10-05 15:03:51 +00:00
|
|
|
// Step 3. Define the database struct
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2019-01-25 09:50:13 +00:00
|
|
|
// Define the actual database struct. This struct needs to be
|
2019-01-25 15:25:17 +00:00
|
|
|
// annotated with `#[salsa::database(..)]`. The list `..` will be the
|
|
|
|
// paths leading to the query group structs for each query group that
|
|
|
|
// this database supports. This attribute macro will generate the
|
|
|
|
// necessary impls so that the database implements the corresponding
|
|
|
|
// traits as well (so, here, `DatabaseStruct` will implement the
|
|
|
|
// `HelloWorldDatabase` trait).
|
2019-01-25 09:50:13 +00:00
|
|
|
//
|
|
|
|
// The database struct can contain basically anything you need, but it
|
|
|
|
// must have a `runtime` field as shown, and you must implement the
|
|
|
|
// `salsa::Database` trait (as shown below).
|
2019-01-25 15:25:17 +00:00
|
|
|
#[salsa::database(HelloWorld)]
|
2018-10-02 09:50:38 +00:00
|
|
|
#[derive(Default)]
|
2018-10-05 08:54:51 +00:00
|
|
|
struct DatabaseStruct {
|
2018-10-07 11:08:22 +00:00
|
|
|
runtime: salsa::Runtime<DatabaseStruct>,
|
2018-10-02 09:50:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tell salsa where to find the runtime in your context.
|
2018-10-05 08:54:51 +00:00
|
|
|
impl salsa::Database for DatabaseStruct {
|
2018-10-07 11:08:22 +00:00
|
|
|
fn salsa_runtime(&self) -> &salsa::Runtime<DatabaseStruct> {
|
2018-10-02 09:50:38 +00:00
|
|
|
&self.runtime
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This shows how to use a query.
|
|
|
|
fn main() {
|
2018-11-01 08:30:54 +00:00
|
|
|
let mut db = DatabaseStruct::default();
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2019-01-25 10:16:57 +00:00
|
|
|
// You cannot access input_string yet, because it does not have a
|
|
|
|
// value. If you do, it will panic. You could create an Option
|
|
|
|
// interface by maintaining a HashSet of inserted keys.
|
2019-01-21 13:45:38 +00:00
|
|
|
// println!("Initially, the length is {}.", db.length(()));
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2019-01-25 10:16:57 +00:00
|
|
|
db.set_input_string((), Arc::new(format!("Hello, world")));
|
2018-10-02 09:50:38 +00:00
|
|
|
|
2018-10-05 09:28:51 +00:00
|
|
|
println!("Now, the length is {}.", db.length(()));
|
2018-10-02 09:50:38 +00:00
|
|
|
}
|