salsa/examples/hello_world/main.rs

105 lines
3.8 KiB
Rust
Raw Normal View History

use salsa::Database;
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
// functions) that are defined in one particular spot. Each query group
// represents some subset of the full set of queries you will use in your
// application. Query groups can also depend on one another: so you might
// have some basic query group A and then another query group B that uses
// the queries from A and adds a few more. (These relationships must form
// a DAG at present, but that is due to Rust's restrictions around
// supertraits, which are likely to be lifted.)
salsa::query_group! {
2018-10-05 08:54:51 +00:00
trait HelloWorldDatabase: salsa::Database {
2018-10-05 15:03:51 +00:00
// For each query, we give the name, input type (here, `()`)
// and the output type `Arc<String>`. Inside the "fn body" we
// give some other configuration.
fn input_string(key: ()) -> Arc<String> {
2018-10-05 15:03:51 +00:00
// The type we will generate to represent this query.
type InputString;
2018-10-05 15:03:51 +00:00
// Specify the queries' "storage" -- in this case, this is
// an *input query*, which means that its value changes
// only when it is explicitly *set* (see the `main`
// function below).
storage input;
}
2018-10-05 15:03:51 +00:00
// This is a *derived query*, meaning its value is specified by
// a function (see Step 2, below).
fn length(key: ()) -> usize {
type Length;
2018-10-05 15:03:51 +00:00
// No explicit storage defaults to `storage memoized;`
//
// The function that defines this query is (by default) a
// function with the same name as the query in the
// containing module (e.g., `length`).
}
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
2018-10-05 08:54:51 +00:00
// Define the actual database struct. This must contain a salsa
2018-10-02 09:50:38 +00:00
// runtime but can also contain anything else you need.
#[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
}
}
// Define the full set of queries that your context needs. This would
2018-10-05 08:54:51 +00:00
// in general combine (and implement) all the database traits in
2018-10-02 09:50:38 +00:00
// your application into one place, allocating storage for all of
// them.
2018-10-05 08:54:51 +00:00
salsa::database_storage! {
struct DatabaseStorage for DatabaseStruct {
impl HelloWorldDatabase {
2018-10-02 09:50:38 +00:00
fn input_string() for InputString;
fn length() for Length;
}
}
}
// This shows how to use a query.
fn main() {
2018-10-05 08:54:51 +00:00
let db = DatabaseStruct::default();
2018-10-02 09:50:38 +00:00
println!("Initially, the length is {}.", db.length(()));
2018-10-02 09:50:38 +00:00
db.query(InputString)
.set((), Arc::new(format!("Hello, world")));
2018-10-02 09:50:38 +00:00
println!("Now, the length is {}.", db.length(()));
2018-10-02 09:50:38 +00:00
}