1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
//! This crate provides salsa's macros and attributes. #![recursion_limit = "256"] extern crate proc_macro; extern crate proc_macro2; #[macro_use] extern crate quote; use proc_macro::TokenStream; mod database_storage; mod parenthesized; mod query_group; /// The decorator that defines a salsa "query group" trait. This is a /// trait that defines everything that a block of queries need to /// execute, as well as defining the queries themselves that are /// exported for others to use. /// /// This macro declares the "prototype" for a group of queries. It will /// expand into a trait and a set of structs, one per query. /// /// For each query, you give the name of the accessor method to invoke /// the query (e.g., `my_query`, below), as well as its parameter /// types and the output type. You also give the name for a query type /// (e.g., `MyQuery`, below) that represents the query, and optionally /// other details, such as its storage. /// /// # Examples /// /// The simplest example is something like this: /// /// ```ignore /// #[salsa::query_group] /// trait TypeckDatabase { /// #[salsa::input] // see below for other legal attributes /// fn my_query(&self, input: u32) -> u64; /// /// /// Queries can have any number of inputs (including zero); if there /// /// is not exactly one input, then the key type will be /// /// a tuple of the input types, so in this case `(u32, f32)`. /// fn other_query(&self, input1: u32, input2: f32) -> u64; /// } /// ``` /// /// Here is a list of legal `salsa::XXX` attributes: /// /// - Storage attributes: control how the query data is stored and set. These /// are described in detail in the section below. /// - `#[salsa::input]` /// - `#[salsa::memoized]` /// - `#[salsa::dependencies]` /// - Query execution: /// - `#[salsa::invoke(path::to::my_fn)]` -- for a non-input, this /// indicates the function to call when a query must be /// recomputed. The default is to call a function in the same /// module with the same name as the query. /// - `#[query_type(MyQueryTypeName)]` specifies the name of the /// dummy struct created for the query. Default is the name of the /// query, in camel case, plus the word "Query" (e.g., /// `MyQueryQuery` and `OtherQueryQuery` in the examples above). /// /// # Storage attributes /// /// Here are the possible storage values for each query. The default /// is `storage memoized`. /// /// ## Input queries /// /// Specifying `storage input` will give you an **input /// query**. Unlike derived queries, whose value is given by a /// function, input queries are explicitly set by doing /// `db.query(QueryType).set(key, value)` (where `QueryType` is the /// `type` specified for the query). Accessing a value that has not /// yet been set will panic. Each time you invoke `set`, we assume the /// value has changed, and so we will potentially re-execute derived /// queries that read (transitively) from this input. /// /// ## Derived queries /// /// Derived queries are specified by a function. /// /// - `#[salsa::memoized]` (the default) -- The result is memoized /// between calls. If the inputs have changed, we will recompute /// the value, but then compare against the old memoized value, /// which can significantly reduce the amount of recomputation /// required in new revisions. This does require that the value /// implements `Eq`. /// - `#[salsa::dependencies]` -- does not cache the value, so it will /// be recomputed every time it is needed. We do track the inputs, however, /// so if they have not changed, then things that rely on this query /// may be known not to have changed. /// /// ## Attribute combinations /// /// Some attributes are mutually exclusive. For example, it is an error to add /// multiple storage specifiers: /// /// ```compile_fail /// # use salsa_macros as salsa; /// #[salsa::query_group] /// trait CodegenDatabase { /// #[salsa::input] /// #[salsa::memoized] /// fn my_query(&self, input: u32) -> u64; /// } /// ``` /// /// It is also an error to annotate a function to `invoke` on an `input` query: /// /// ```compile_fail /// # use salsa_macros as salsa; /// #[salsa::query_group] /// trait CodegenDatabase { /// #[salsa::input] /// #[salsa::invoke(typeck::my_query)] /// fn my_query(&self, input: u32) -> u64; /// } /// ``` #[proc_macro_attribute] pub fn query_group(args: TokenStream, input: TokenStream) -> TokenStream { query_group::query_group(args, input) } /// This attribute is placed on your database struct. It takes a list of the /// query groups that your database supports. The format looks like so: /// /// ```rust,ignore /// #[salsa::database(MyQueryGroup1, MyQueryGroup2)] /// struct MyDatabase { /// runtime: salsa::Runtime<MyDatabase>, // <-- your database will need this field, too /// } /// ``` /// /// Here, the struct `MyDatabase` would support the two query groups /// `MyQueryGroup1` and `MyQueryGroup2`. In addition to the `database` /// attribute, the struct needs to have a `runtime` field (of type /// [`salsa::Runtime`]) and to implement the `salsa::Database` trait. /// /// See [the `hello_world` example][hw] for more details. /// /// [`salsa::Runtime`]: struct.Runtime.html /// [hw]: https://github.com/salsa-rs/salsa/tree/master/examples/hello_world #[proc_macro_attribute] pub fn database(args: TokenStream, input: TokenStream) -> TokenStream { database_storage::database(args, input) }