diff --git a/Cargo.toml b/Cargo.toml index 98b9fb8c..eb8cc4c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ lock_api = "0.1.4" indexmap = "1.0.1" log = "0.4.5" smallvec = "0.6.5" +salsa_macros = { version = "0.9", path = "components/salsa_macros" } [dev-dependencies] diff = "0.1.0" diff --git a/components/salsa_macros/Cargo.toml b/components/salsa_macros/Cargo.toml new file mode 100644 index 00000000..8879d648 --- /dev/null +++ b/components/salsa_macros/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "salsa_macros" +version = "0.9.1" +authors = ["Niko Matsakis "] +edition = "2018" +license = "Apache-2.0 OR MIT" +repository = "https://github.com/salsa-rs/salsa" +description = "Procedural macros for the salsa crate" +readme = "README.md" + +[lib] +proc-macro = true + +[dependencies] +heck = "0.3" +proc-macro2 = "0.4" +quote = "0.6" +syn = { version = "0.15", features = ["full", "extra-traits"] } diff --git a/components/salsa_macros/LICENSE-APACHE b/components/salsa_macros/LICENSE-APACHE new file mode 120000 index 00000000..1cd601d0 --- /dev/null +++ b/components/salsa_macros/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/components/salsa_macros/LICENSE-MIT b/components/salsa_macros/LICENSE-MIT new file mode 120000 index 00000000..b2cfbdc7 --- /dev/null +++ b/components/salsa_macros/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file diff --git a/components/salsa_macros/README.md b/components/salsa_macros/README.md new file mode 120000 index 00000000..fe840054 --- /dev/null +++ b/components/salsa_macros/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/components/salsa_macros/src/lib.rs b/components/salsa_macros/src/lib.rs new file mode 100644 index 00000000..9a266696 --- /dev/null +++ b/components/salsa_macros/src/lib.rs @@ -0,0 +1,369 @@ +//! This crate provides salsa's macros and attributes. + +#![recursion_limit = "128"] + +extern crate proc_macro; +extern crate proc_macro2; +#[macro_use] +extern crate quote; + +use heck::CamelCase; +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::ToTokens; +use syn::{parse_macro_input, AttributeArgs, FnArg, Ident, ItemTrait, ReturnType, TraitItem}; + +/// 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::XXX] // see below for 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(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::volatile]` +/// - `#[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 fo 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::volatile]` -- indicates that the inputs are not fully +/// captured by salsa. The result will be recomputed once per revision. +/// - `#[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: +/// +/// ```ignore +/// #[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: +/// +/// ```ignore +/// #[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 { + let _args = parse_macro_input!(args as AttributeArgs); + let input = parse_macro_input!(input as ItemTrait); + // println!("args: {:#?}", args); + // println!("input: {:#?}", input); + + let trait_vis = input.vis; + let trait_name = input.ident; + let _generics = input.generics.clone(); + + // Decompose the trait into the corresponding queries. + let mut queries = vec![]; + for item in input.items { + match item { + TraitItem::Method(method) => { + let mut storage = QueryStorage::Memoized; + let mut invoke = None; + let mut query_type = Ident::new( + &format!("{}Query", method.sig.ident.to_string().to_camel_case()), + Span::call_site(), + ); + let mut num_storages = 0; + + // Extract attributes. + let mut attrs = vec![]; + for attr in method.attrs { + // Leave non-salsa attributes untouched. These are + // attributes that don't start with `salsa::` or don't have + // exactly two segments in their path. + if is_salsa_attr_path(&attr.path) { + attrs.push(attr); + continue; + } + + // Keep the salsa attributes around. + let name = attr.path.segments[1].ident.to_string(); + let tts = attr.tts.into(); + match name.as_str() { + "memoized" => { + storage = QueryStorage::Memoized; + num_storages += 1; + } + "volatile" => { + storage = QueryStorage::Volatile; + num_storages += 1; + } + "dependencies" => { + storage = QueryStorage::Dependencies; + num_storages += 1; + } + "input" => { + storage = QueryStorage::Input; + num_storages += 1; + } + "invoke" => { + invoke = Some(parse_macro_input!(tts as Parenthesized).0); + } + "query_type" => { + query_type = parse_macro_input!(tts as Parenthesized).0; + } + _ => panic!("unknown salsa attribute `{}`", name), + } + } + + // Check attribute combinations. + if num_storages > 1 { + panic!("multiple storage attributes specified"); + } + if invoke.is_some() && storage == QueryStorage::Input { + panic!("#[salsa::invoke] cannot be set on #[salsa::input] queries"); + } + + // Extract keys. + let mut iter = method.sig.decl.inputs.iter(); + match iter.next() { + Some(FnArg::SelfRef(sr)) if sr.mutability.is_none() => (), + _ => panic!( + "first argument of query `{}` must be `&self` or `&mut self`", + method.sig.ident + ), + } + let mut keys = vec![]; + for arg in iter { + match *arg { + FnArg::Captured(ref arg) => { + keys.push(arg.ty.clone()); + } + ref a => panic!("unsupported argument `{:?}` of `{}`", a, method.sig.ident), + } + } + + // Extract value. + let value = match method.sig.decl.output { + ReturnType::Type(_, ref ty) => ty.as_ref().clone(), + ref r => panic!( + "unsupported return type `{:?}` of `{}`", + r, method.sig.ident + ), + }; + + queries.push(Query { + query_type, + fn_name: method.sig.ident.clone(), + attrs, + storage, + keys, + value, + invoke, + }); + } + _ => (), + } + } + + // Emit the trait itself. + let mut output = { + let mut queries_as_tokens = proc_macro2::TokenStream::new(); + for query in &queries { + let key_names: &Vec<_> = &(0..query.keys.len()) + .map(|i| Ident::new(&format!("key{}", i), Span::call_site())) + .collect(); + let keys = &query.keys; + let value = &query.value; + let fn_name = &query.fn_name; + let qt = &query.query_type; + let attrs = &query.attrs; + let expanded = quote! { + #(#attrs)* + fn #fn_name(&self, #(#key_names: #keys),*) -> #value { + >::get_query_table(self).get((#(#key_names),*)) + } + }; + queries_as_tokens.extend(expanded); + } + + let attrs = &input.attrs; + let qts = queries.iter().map(|q| &q.query_type); + let bounds = &input.supertraits; + quote! { + #(#attrs)* + #trait_vis trait #trait_name : #(salsa::plumbing::GetQueryTable<#qts> +)* #bounds { + #queries_as_tokens + } + } + }; + + // Emit the query types. + for query in queries { + let qt = &query.query_type; + let storage = Ident::new( + match query.storage { + QueryStorage::Memoized => "MemoizedStorage", + QueryStorage::Volatile => "VolatileStorage", + QueryStorage::Dependencies => "DependencyStorage", + QueryStorage::Input => "InputStorage", + }, + Span::call_site(), + ); + let keys = &query.keys; + let value = &query.value; + + // Emit the query struct and implement the Query trait on it. + output.extend(quote! { + #[derive(Default, Debug)] + #trait_vis struct #qt; + + impl salsa::Query for #qt + where + DB: #trait_name, + { + type Key = (#(#keys),*); + type Value = #value; + type Storage = salsa::plumbing::#storage; + } + }); + + // Implement the QueryFunction trait for all queries except inputs. + if query.storage != QueryStorage::Input { + let span = query.fn_name.span(); + let key_names: &Vec<_> = &(0..query.keys.len()) + .map(|i| Ident::new(&format!("key{}", i), Span::call_site())) + .collect(); + let key_pattern = if query.keys.len() == 1 { + quote! { #(#key_names),* } + } else { + quote! { (#(#key_names),*) } + }; + let invoke = match &query.invoke { + Some(i) => i.into_token_stream(), + None => query.fn_name.into_token_stream(), + }; + output.extend(quote_spanned! {span=> + impl salsa::plumbing::QueryFunction for #qt + where + DB: #trait_name, + { + fn execute(db: &DB, #key_pattern: >::Key) + -> >::Value { + #invoke(db, #(#key_names),*) + } + } + }); + } + } + + output.into() +} + +fn is_salsa_attr_path(path: &syn::Path) -> bool { + path.segments + .first() + .map(|s| s.value().ident != "salsa") + .unwrap_or(true) + || path.segments.len() != 2 +} + +#[derive(Debug)] +struct Query { + fn_name: Ident, + attrs: Vec, + query_type: Ident, + storage: QueryStorage, + keys: Vec, + value: syn::Type, + invoke: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum QueryStorage { + Memoized, + Volatile, + Dependencies, + Input, +} + +struct Parenthesized(pub T); + +impl syn::parse::Parse for Parenthesized +where + T: syn::parse::Parse, +{ + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let content; + syn::parenthesized!(content in input); + content.parse::().map(Parenthesized) + } +} diff --git a/examples/compiler/class_table.rs b/examples/compiler/class_table.rs index 0e009a28..7d89bce8 100644 --- a/examples/compiler/class_table.rs +++ b/examples/compiler/class_table.rs @@ -1,23 +1,16 @@ use crate::compiler; use std::sync::Arc; -salsa::query_group! { - pub trait ClassTableDatabase: compiler::CompilerDatabase { - /// Get the fields. - fn fields(class: DefId) -> Arc> { - type Fields; - } +#[salsa::query_group] +pub trait ClassTableDatabase: compiler::CompilerDatabase { + /// Get the fields. + fn fields(&self, class: DefId) -> Arc>; - /// Get the list of all classes - fn all_classes() -> Arc> { - type AllClasses; - } + /// Get the list of all classes + fn all_classes(&self) -> Arc>; - /// Get the list of all fields - fn all_fields() -> Arc> { - type AllFields; - } - } + /// Get the list of all fields + fn all_fields(&self) -> Arc>; } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] diff --git a/examples/compiler/implementation.rs b/examples/compiler/implementation.rs index a81df4ce..2e48fc23 100644 --- a/examples/compiler/implementation.rs +++ b/examples/compiler/implementation.rs @@ -39,9 +39,9 @@ impl salsa::Database for DatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for DatabaseImpl { impl class_table::ClassTableDatabase { - fn all_classes() for class_table::AllClasses; - fn all_fields() for class_table::AllFields; - fn fields() for class_table::Fields; + fn all_classes() for class_table::AllClassesQuery; + fn all_fields() for class_table::AllFieldsQuery; + fn fields() for class_table::FieldsQuery; } } } diff --git a/examples/hello_world/README.md b/examples/hello_world/README.md index 5c07a29a..1be97636 100644 --- a/examples/hello_world/README.md +++ b/examples/hello_world/README.md @@ -12,34 +12,33 @@ 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.) -Each query group is defined via an invocation of `salsa::query_group!` -macro. This is the invocation used in `hello_world`: +Each query group is defined via a trait with the +`#[salsa::query_group]` decorator attached to it. `salsa::query_group` +is a procedural macro that will process the trait -- it will produce +not only the trait you specified, but also various additional types +you can later use and name. ```rust -salsa::query_group! { - trait HelloWorldDatabase: salsa::Database { - fn input_string(key: ()) -> Arc { - type InputString; - storage input; - } +#[salsa::query_group] +trait HelloWorldDatabase: salsa::Database { + #[salsa::input] + #[salsa::query_type(InputString)] + fn input_string(&self, key: ()) -> Arc; - fn length(key: ()) -> usize { - type Length; - } - } + fn length(&self, key: ()) -> usize; } ``` -This invocation will in fact expand to a number of things you can -later use and name. First and foremost is the **query group trait**, -here called `HelloWorldDatabase`. As the name suggests, this trait -will ultimately be implemented by the **database**, which is the -struct in your application that contains the store for all queries and -any other global state that persists beyond a single query execution. -In writing your application, though, we never work with a concrete -database struct: instead we work against a generic struct through -traits, thus capturing the subset of functionality that we actually -need. +Each query group trait represents a self-contained block of queries +that can invoke each other and so forth. Your final database may +implement many such traits, thus combining many groups of queries into +the final program. Query groups are thus kind of analogous to Rust +crates: they represent a kind of "library" of queries that your final +program can use. Since we don't know the full set of queries that our +code may be combined with, when implementing a query group we don't +with a concrete database struct: instead we work against a generic +struct through traits, thus capturing the subset of functionality that +we actually need. The `HelloWorldDatabase` trait has one supertrait: `salsa::Database`. If we were defining more query groups in our @@ -59,19 +58,19 @@ the "fn body" is obviously not real Rust syntax. Rather, it's just used to specify a few bits of metadata about the query. We'll see how to define the fn body in the next step. -**For each query.** For each query, we must **always** define a `type` -(e.g., `type InputString;`). The macro will define a type with this -name alongside the trait: you can use this name later to specify which -query you are talking about. This is needed for some of the more -advanced methods (we'll discuss them later). +**For each query.** For each query, the procedural macro will emit a +"query type", which is a kind of dummy struct that can be used to +refer to the query (we'll see an example of referencing this struct +later). For a query `foo_bar`, the struct is by default named +`FooBarQuery` -- but that name can be overridden with the +`#[salsa::query_type]` attribute. In our example, we override the +query type for `input_string` to be `InputString` but left `length` +alone (so it defaults to `LengthQuery`). -You can also optionally define the **storage** for a query via a -declaration like `storage ;`. The most common kind of storage is -either *memoized* (the default) or *input*. An *input* is a special -sort of query that is not defined by a function: rather, it gets its -values via explicit `set` operations (we'll see them later). In our -case, we define one input query (`input_string`) and one memoized -query (`length`). +You can also use the `#[salsa::input]` attribute to designate +the "inputs" to the system. The values for input queries are not +generated via a function but rather by explicit `set` operations, +as we'll see later. They are the starting points for your computation. ### Step 2: Define the query functions @@ -79,9 +78,9 @@ Once you've defined your query group, you have to give the function definition for every non-input query. In our case, that is the query `length`. To do this, you simply define a function with the appropriate name in the same module as the query group; if you would -prefer to use a different name or location, you write `use fn -path::to::other_fn;` in the query definition to tell us where to find -it. +prefer to use a different name or location, you add an attribute like +`#[salsa::invoke(path::to::other_fn)]` in the query definition to tell +us where to find it. The query function for `length` looks like: diff --git a/examples/hello_world/main.rs b/examples/hello_world/main.rs index 4c9a6304..b206e7e8 100644 --- a/examples/hello_world/main.rs +++ b/examples/hello_world/main.rs @@ -12,34 +12,24 @@ use std::sync::Arc; // 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! { - trait HelloWorldDatabase: salsa::Database { - // For each query, we give the name, input type (here, `()`) - // and the output type `Arc`. Inside the "fn body" we - // give some other configuration. - fn input_string(key: ()) -> Arc { - // The type we will generate to represent this query. - type InputString; +#[salsa::query_group] +trait HelloWorldDatabase: salsa::Database { + // For each query, we give the name, input type (here, `()`) + // and the output type `Arc`. We can use attributes to + // give other configuration: + // + // - `salsa::input` indicates that this is an "input" to the system, + // which must be explicitly set. + // - `salsa::query_type` controls the name of the dummy struct + // that represents this query. We'll see it referenced + // later. The default would have been `InputStringQuery`. + #[salsa::input] + #[salsa::query_type(InputString)] + fn input_string(&self, key: ()) -> Arc; - // 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; - } - - // This is a *derived query*, meaning its value is specified by - // a function (see Step 2, below). - fn length(key: ()) -> usize { - type Length; - - // 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`). - } - } + // This is a *derived query*, meaning its value is specified by + // a function (see Step 2, below). + fn length(&self, key: ()) -> usize; } /////////////////////////////////////////////////////////////////////////// @@ -86,7 +76,7 @@ salsa::database_storage! { struct DatabaseStorage for DatabaseStruct { impl HelloWorldDatabase { fn input_string() for InputString; - fn length() for Length; + fn length() for LengthQuery; } } } diff --git a/src/lib.rs b/src/lib.rs index 0cdd06e6..224dd0bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -474,293 +474,6 @@ where } } -/// A macro that helps in defining the "context trait" of a given -/// module. 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 -/// trait TypeckDatabase { -/// query_group! { -/// /// Comments or other attributes can go here -/// fn my_query(input: u32) -> u64 { -/// type MyQuery; -/// storage memoized; // optional, this is the default -/// use fn path::to::fn; // optional, default is `my_query` -/// } -/// -/// /// Queries can have any number of inputs; the key type will be -/// /// a tuple of the input types, so in this case `(u32, f32)`. -/// fn other_query(input1: u32, input2: f32) -> u64 { -/// type OtherQuery; -/// } -/// } -/// } -/// ``` -/// -/// # Storage modes -/// -/// 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 explicit 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. -/// -/// - `storage memoized` -- 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`. -/// - `storage volatile` -- indicates that the inputs are not fully -/// captured by salsa. The result will be recomputed once per revision. -/// - `storage 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. -#[macro_export] -macro_rules! query_group { - ( - $(#[$attr:meta])* $v:vis trait $name:ident { $($t:tt)* } - ) => { - $crate::query_group! { - attr[$(#[$attr])*]; - headers[$v, $name, ]; - tokens[{ $($t)* }]; - } - }; - - ( - $(#[$attr:meta])* $v:vis trait $name:ident : $($t:tt)* - ) => { - $crate::query_group! { - attr[$(#[$attr])*]; - headers[$v, $name, ]; - tokens[$($t)*]; - } - }; - - // Base case: found the trait body - ( - attr[$($trait_attr:tt)*]; - headers[$v:vis, $query_trait:ident, $($header:tt)*]; - tokens[{ - $( - $(#[$method_attr:meta])* - fn $method_name:ident($($key_name:ident: $key_ty:ty),* $(,)*) -> $value_ty:ty { - type $QueryType:ident; - $(storage $storage:tt;)* // FIXME(rust-lang/rust#48075) should be `?` - $(use fn $fn_path:path;)* // FIXME(rust-lang/rust#48075) should be `?` - } - )* - }]; - ) => { - $($trait_attr)* $v trait $query_trait: $($crate::plumbing::GetQueryTable<$QueryType> +)* $($header)* { - $( - $(#[$method_attr])* - fn $method_name(&self, $($key_name: $key_ty),*) -> $value_ty { - >::get_query_table(self) - .get(($($key_name),*)) - } - )* - } - - $( - #[derive(Default, Debug)] - $v struct $QueryType; - - impl $crate::Query for $QueryType - where - DB: $query_trait, - { - type Key = ($($key_ty),*); - type Value = $value_ty; - type Storage = $crate::query_group! { @storage_ty[DB, Self, $($storage)*] }; - } - - $crate::query_group! { - @query_fn[ - storage($($storage)*); - method_name($method_name); - fn_path($($fn_path)*); - db_trait($query_trait); - query_type($QueryType); - key($($key_name: $key_ty),*); - ] - } - )* - }; - - ( - @query_fn[ - storage(input); - method_name($method_name:ident); - fn_path(); - $($rest:tt)* - ] - ) => { - // do nothing for `storage input`, presuming they did not write an explicit `use fn` - }; - - ( - @query_fn[ - storage(input); - method_name($method_name:ident); - fn_path($fn_path:path); - $($rest:tt)* - ] - ) => { - // error for `storage input` with an explicit `use fn` - compile_error! { - "cannot have `storage input` combined with `use fn`" - } - }; - - ( - @query_fn[ - storage($($storage:ident)*); - method_name($method_name:ident); - fn_path(); - $($rest:tt)* - ] - ) => { - // default to `use fn $method_name` - $crate::query_group! { - @query_fn[ - storage($($storage)*); - method_name($method_name); - fn_path($method_name); - $($rest)* - ] - } - }; - - // Handle fns of one argument: once parenthesized patterns are stable on beta, - // we can remove this special case. - ( - @query_fn[ - storage($($storage:ident)*); - method_name($method_name:ident); - fn_path($fn_path:path); - db_trait($DbTrait:path); - query_type($QueryType:ty); - key($key_name:ident: $key_ty:ty); - ] - ) => { - impl $crate::plumbing::QueryFunction for $QueryType - where DB: $DbTrait - { - fn execute(db: &DB, $key_name: >::Key) - -> >::Value - { - $fn_path(db, $key_name) - } - } - }; - - // Handle fns of N arguments: once parenthesized patterns are stable on beta, - // we can use this code for all cases. - ( - @query_fn[ - storage($($storage:ident)*); - method_name($method_name:ident); - fn_path($fn_path:path); - db_trait($DbTrait:path); - query_type($QueryType:ty); - key($($key_name:ident: $key_ty:ty),*); - ] - ) => { - impl $crate::plumbing::QueryFunction for $QueryType - where DB: $DbTrait - { - fn execute(db: &DB, ($($key_name),*): >::Key) - -> >::Value - { - $fn_path(db, $($key_name),*) - } - } - }; - - // Recursive case: found some more part of the trait header. - // Keep pulling out tokens until we find the body. - ( - attr[$($attr:tt)*]; - headers[$($headers:tt)*]; - tokens[$token:tt $($tokens:tt)*]; - ) => { - $crate::query_group! { - attr[$($attr)*]; - headers[$($headers)* $token]; - tokens[$($tokens)*]; - } - }; - - // Generate storage type - ( - // Default case: - @storage_ty[$DB:ident, $Self:ident, ] - ) => { - $crate::query_group! { @storage_ty[$DB, $Self, memoized] } - }; - - ( - @storage_ty[$DB:ident, $Self:ident, memoized] - ) => { - $crate::plumbing::MemoizedStorage<$DB, $Self> - }; - - ( - @storage_ty[$DB:ident, $Self:ident, volatile] - ) => { - $crate::plumbing::VolatileStorage<$DB, $Self> - }; - - ( - @storage_ty[$DB:ident, $Self:ident, dependencies] - ) => { - $crate::plumbing::DependencyStorage<$DB, $Self> - }; - - ( - @storage_ty[$DB:ident, $Self:ident, input] - ) => { - $crate::plumbing::InputStorage - }; - - ( - @storage_ty[$DB:ident, $Self:ident, $storage:tt] - ) => { - compile_error! { - "invalid storage specification" - } - }; -} - /// This macro generates the "query storage" that goes into your database. /// It requires you to list all of the query groups that you need as well /// as the queries within those groups. The format looks like so: @@ -917,3 +630,10 @@ macro_rules! database_storage { )* }; } + +// Re-export the procedural macros. +#[allow(unused_imports)] +#[macro_use] +extern crate salsa_macros; +#[doc(hidden)] +pub use salsa_macros::*; diff --git a/tests/cycles.rs b/tests/cycles.rs index 39e887aa..947a80ea 100644 --- a/tests/cycles.rs +++ b/tests/cycles.rs @@ -12,32 +12,23 @@ impl salsa::Database for DatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for DatabaseImpl { impl Database { - fn memoized_a() for MemoizedA; - fn memoized_b() for MemoizedB; - fn volatile_a() for VolatileA; - fn volatile_b() for VolatileB; + fn memoized_a() for MemoizedAQuery; + fn memoized_b() for MemoizedBQuery; + fn volatile_a() for VolatileAQuery; + fn volatile_b() for VolatileBQuery; } } } -salsa::query_group! { - trait Database: salsa::Database { - // `a` and `b` depend on each other and form a cycle - fn memoized_a() -> () { - type MemoizedA; - } - fn memoized_b() -> () { - type MemoizedB; - } - fn volatile_a() -> () { - type VolatileA; - storage volatile; - } - fn volatile_b() -> () { - type VolatileB; - storage volatile; - } - } +#[salsa::query_group] +trait Database: salsa::Database { + // `a` and `b` depend on each other and form a cycle + fn memoized_a(&self) -> (); + fn memoized_b(&self) -> (); + #[salsa::volatile] + fn volatile_a(&self) -> (); + #[salsa::volatile] + fn volatile_b(&self) -> (); } fn memoized_a(db: &impl Database) -> () { diff --git a/tests/gc/db.rs b/tests/gc/db.rs index 7ccaa5b3..83d4d959 100644 --- a/tests/gc/db.rs +++ b/tests/gc/db.rs @@ -16,13 +16,13 @@ impl salsa::Database for DatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for DatabaseImpl { impl group::GcDatabase { - fn min() for group::Min; - fn max() for group::Max; - fn use_triangular() for group::UseTriangular; - fn fibonacci() for group::Fibonacci; - fn triangular() for group::Triangular; - fn compute() for group::Compute; - fn compute_all() for group::ComputeAll; + fn min() for group::MinQuery; + fn max() for group::MaxQuery; + fn use_triangular() for group::UseTriangularQuery; + fn fibonacci() for group::FibonacciQuery; + fn triangular() for group::TriangularQuery; + fn compute() for group::ComputeQuery; + fn compute_all() for group::ComputeAllQuery; } } } diff --git a/tests/gc/derived_tests.rs b/tests/gc/derived_tests.rs index ca2bab67..473d52eb 100644 --- a/tests/gc/derived_tests.rs +++ b/tests/gc/derived_tests.rs @@ -18,19 +18,19 @@ fn compute_one() { let mut db = db::DatabaseImpl::default(); // Will compute fibonacci(5) - db.query_mut(UseTriangular).set(5, false); + db.query_mut(UseTriangularQuery).set(5, false); db.compute(5); db.salsa_runtime().next_revision(); assert_keys! { db, - Triangular => (), - Fibonacci => (0, 1, 2, 3, 4, 5), - Compute => (5), - UseTriangular => (5), - Min => (), - Max => (), + TriangularQuery => (), + FibonacciQuery => (0, 1, 2, 3, 4, 5), + ComputeQuery => (5), + UseTriangularQuery => (5), + MinQuery => (), + MaxQuery => (), } // Memoized, but will compute fibonacci(5) again @@ -39,12 +39,12 @@ fn compute_one() { assert_keys! { db, - Triangular => (), - Fibonacci => (5), - Compute => (5), - UseTriangular => (5), - Min => (), - Max => (), + TriangularQuery => (), + FibonacciQuery => (5), + ComputeQuery => (5), + UseTriangularQuery => (5), + MinQuery => (), + MaxQuery => (), } } @@ -53,11 +53,11 @@ fn compute_switch() { let mut db = db::DatabaseImpl::default(); // Will compute fibonacci(5) - db.query_mut(UseTriangular).set(5, false); + db.query_mut(UseTriangularQuery).set(5, false); assert_eq!(db.compute(5), 5); // Change to triangular mode - db.query_mut(UseTriangular).set(5, true); + db.query_mut(UseTriangularQuery).set(5, true); // Now computes triangular(5) assert_eq!(db.compute(5), 15); @@ -66,12 +66,12 @@ fn compute_switch() { // are not relevant to the most recent value of `Compute` assert_keys! { db, - Triangular => (0, 1, 2, 3, 4, 5), - Fibonacci => (0, 1, 2, 3, 4, 5), - Compute => (5), - UseTriangular => (5), - Min => (), - Max => (), + TriangularQuery => (0, 1, 2, 3, 4, 5), + FibonacciQuery => (0, 1, 2, 3, 4, 5), + ComputeQuery => (5), + UseTriangularQuery => (5), + MinQuery => (), + MaxQuery => (), } db.sweep_all(SweepStrategy::default()); @@ -79,12 +79,12 @@ fn compute_switch() { // Now we just have `Triangular` and not `Fibonacci` assert_keys! { db, - Triangular => (0, 1, 2, 3, 4, 5), - Fibonacci => (), - Compute => (5), - UseTriangular => (5), - Min => (), - Max => (), + TriangularQuery => (0, 1, 2, 3, 4, 5), + FibonacciQuery => (), + ComputeQuery => (5), + UseTriangularQuery => (5), + MinQuery => (), + MaxQuery => (), } // Now run `compute` *again* in next revision. @@ -95,12 +95,12 @@ fn compute_switch() { // We keep triangular, but just the outermost one. assert_keys! { db, - Triangular => (5), - Fibonacci => (), - Compute => (5), - UseTriangular => (5), - Min => (), - Max => (), + TriangularQuery => (5), + FibonacciQuery => (), + ComputeQuery => (5), + UseTriangularQuery => (5), + MinQuery => (), + MaxQuery => (), } } @@ -110,11 +110,11 @@ fn compute_all() { let mut db = db::DatabaseImpl::default(); for i in 0..6 { - db.query_mut(UseTriangular).set(i, (i % 2) != 0); + db.query_mut(UseTriangularQuery).set(i, (i % 2) != 0); } - db.query_mut(Min).set((), 0); - db.query_mut(Max).set((), 6); + db.query_mut(MinQuery).set((), 0); + db.query_mut(MaxQuery).set((), 6); db.compute_all(); db.salsa_runtime().next_revision(); @@ -123,42 +123,42 @@ fn compute_all() { assert_keys! { db, - Triangular => (1, 3, 5), - Fibonacci => (0, 2, 4), - Compute => (0, 1, 2, 3, 4, 5), - ComputeAll => (()), - UseTriangular => (0, 1, 2, 3, 4, 5), - Min => (()), - Max => (()), + TriangularQuery => (1, 3, 5), + FibonacciQuery => (0, 2, 4), + ComputeQuery => (0, 1, 2, 3, 4, 5), + ComputeAllQuery => (()), + UseTriangularQuery => (0, 1, 2, 3, 4, 5), + MinQuery => (()), + MaxQuery => (()), } // Reduce the range to exclude index 5. - db.query_mut(Max).set((), 5); + db.query_mut(MaxQuery).set((), 5); db.compute_all(); assert_keys! { db, - Triangular => (1, 3, 5), - Fibonacci => (0, 2, 4), - Compute => (0, 1, 2, 3, 4, 5), - ComputeAll => (()), - UseTriangular => (0, 1, 2, 3, 4, 5), - Min => (()), - Max => (()), + TriangularQuery => (1, 3, 5), + FibonacciQuery => (0, 2, 4), + ComputeQuery => (0, 1, 2, 3, 4, 5), + ComputeAllQuery => (()), + UseTriangularQuery => (0, 1, 2, 3, 4, 5), + MinQuery => (()), + MaxQuery => (()), } db.sweep_all(SweepStrategy::default()); // We no longer used `Compute(5)` and `Triangular(5)`; note that - // `UseTriangular(5)` is not collected, as it is an input. + // `UseTriangularQuery(5)` is not collected, as it is an input. assert_keys! { db, - Triangular => (1, 3), - Fibonacci => (0, 2, 4), - Compute => (0, 1, 2, 3, 4), - ComputeAll => (()), - UseTriangular => (0, 1, 2, 3, 4, 5), - Min => (()), - Max => (()), + TriangularQuery => (1, 3), + FibonacciQuery => (0, 2, 4), + ComputeQuery => (0, 1, 2, 3, 4), + ComputeAllQuery => (()), + UseTriangularQuery => (0, 1, 2, 3, 4, 5), + MinQuery => (()), + MaxQuery => (()), } } diff --git a/tests/gc/discard_values.rs b/tests/gc/discard_values.rs index 2de74f40..4de16934 100644 --- a/tests/gc/discard_values.rs +++ b/tests/gc/discard_values.rs @@ -1,5 +1,5 @@ use crate::db; -use crate::group::{Fibonacci, GcDatabase}; +use crate::group::{FibonacciQuery, GcDatabase}; use salsa::debug::DebugQueryTable; use salsa::{Database, SweepStrategy}; @@ -9,7 +9,7 @@ fn sweep_default() { db.fibonacci(5); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 6); db.salsa_runtime().next_revision(); @@ -20,7 +20,7 @@ fn sweep_default() { // fibonacci is a constant, so it will not be invalidated, // hence we keep 3 and 5 but remove the rest. db.sweep_all(SweepStrategy::default()); - let mut k: Vec<_> = db.query(Fibonacci).keys(); + let mut k: Vec<_> = db.query(FibonacciQuery).keys(); k.sort(); assert_eq!(k, vec![3, 5]); @@ -31,7 +31,7 @@ fn sweep_default() { // Same but we discard values this time. db.sweep_all(SweepStrategy::default().discard_values()); - let mut k: Vec<_> = db.query(Fibonacci).keys(); + let mut k: Vec<_> = db.query(FibonacciQuery).keys(); k.sort(); assert_eq!(k, vec![3, 5]); diff --git a/tests/gc/group.rs b/tests/gc/group.rs index 8c4aa41f..135b2a50 100644 --- a/tests/gc/group.rs +++ b/tests/gc/group.rs @@ -1,38 +1,23 @@ use crate::log::HasLog; -salsa::query_group! { - pub(crate) trait GcDatabase: salsa::Database + HasLog { - fn min() -> usize { - type Min; - storage input; - } +#[salsa::query_group] +pub(crate) trait GcDatabase: salsa::Database + HasLog { + #[salsa::input] + fn min(&self) -> usize; - fn max() -> usize { - type Max; - storage input; - } + #[salsa::input] + fn max(&self) -> usize; - fn use_triangular(key: usize) -> bool { - type UseTriangular; - storage input; - } + #[salsa::input] + fn use_triangular(&self, key: usize) -> bool; - fn fibonacci(key: usize) -> usize { - type Fibonacci; - } + fn fibonacci(&self, key: usize) -> usize; - fn triangular(key: usize) -> usize { - type Triangular; - } + fn triangular(&self, key: usize) -> usize; - fn compute(key: usize) -> usize { - type Compute; - } + fn compute(&self, key: usize) -> usize; - fn compute_all() -> Vec { - type ComputeAll; - } - } + fn compute_all(&self) -> Vec; } fn fibonacci(db: &impl GcDatabase, key: usize) -> usize { diff --git a/tests/gc/shallow_constant_tests.rs b/tests/gc/shallow_constant_tests.rs index 1659a073..a6405778 100644 --- a/tests/gc/shallow_constant_tests.rs +++ b/tests/gc/shallow_constant_tests.rs @@ -1,5 +1,5 @@ use crate::db; -use crate::group::{Fibonacci, GcDatabase}; +use crate::group::{FibonacciQuery, GcDatabase}; use salsa::debug::DebugQueryTable; use salsa::{Database, SweepStrategy}; @@ -13,7 +13,7 @@ fn one_rev() { db.fibonacci(5); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 6); // Everything was used in this revision, so @@ -28,7 +28,7 @@ fn two_rev_nothing() { db.fibonacci(5); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 6); db.salsa_runtime().next_revision(); @@ -37,7 +37,7 @@ fn two_rev_nothing() { // everything gets collected. db.sweep_all(SweepStrategy::default()); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 0); } @@ -47,7 +47,7 @@ fn two_rev_one_use() { db.fibonacci(5); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 6); db.salsa_runtime().next_revision(); @@ -58,7 +58,7 @@ fn two_rev_one_use() { // hence we keep `fibonacci(5)` but remove 0..=4. db.sweep_all(SweepStrategy::default()); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k, vec![5]); } @@ -68,7 +68,7 @@ fn two_rev_two_uses() { db.fibonacci(5); - let k: Vec<_> = db.query(Fibonacci).keys(); + let k: Vec<_> = db.query(FibonacciQuery).keys(); assert_eq!(k.len(), 6); db.salsa_runtime().next_revision(); @@ -80,7 +80,7 @@ fn two_rev_two_uses() { // hence we keep 3 and 5 but remove the rest. db.sweep_all(SweepStrategy::default()); - let mut k: Vec<_> = db.query(Fibonacci).keys(); + let mut k: Vec<_> = db.query(FibonacciQuery).keys(); k.sort(); assert_eq!(k, vec![3, 5]); } diff --git a/tests/incremental/constants.rs b/tests/incremental/constants.rs index f7bc960f..6c2c0aaf 100644 --- a/tests/incremental/constants.rs +++ b/tests/incremental/constants.rs @@ -2,17 +2,12 @@ use crate::implementation::{TestContext, TestContextImpl}; use salsa::debug::DebugQueryTable; use salsa::Database; -salsa::query_group! { - pub(crate) trait ConstantsDatabase: TestContext { - fn constants_input(key: char) -> usize { - type ConstantsInput; - storage input; - } +#[salsa::query_group] +pub(crate) trait ConstantsDatabase: TestContext { + #[salsa::input] + fn constants_input(&self, key: char) -> usize; - fn constants_add(keys: (char, char)) -> usize { - type ConstantsAdd; - } - } + fn constants_add(&self, keys: (char, char)) -> usize; } fn constants_add(db: &impl ConstantsDatabase, (key1, key2): (char, char)) -> usize { @@ -24,8 +19,8 @@ fn constants_add(db: &impl ConstantsDatabase, (key1, key2): (char, char)) -> usi #[should_panic] fn invalidate_constant() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set_constant('a', 44); - db.query_mut(ConstantsInput).set_constant('a', 66); + db.query_mut(ConstantsInputQuery).set_constant('a', 44); + db.query_mut(ConstantsInputQuery).set_constant('a', 66); } #[test] @@ -34,13 +29,13 @@ fn invalidate_constant_1() { let db = &mut TestContextImpl::default(); // Not constant: - db.query_mut(ConstantsInput).set('a', 44); + db.query_mut(ConstantsInputQuery).set('a', 44); // Becomes constant: - db.query_mut(ConstantsInput).set_constant('a', 44); + db.query_mut(ConstantsInputQuery).set_constant('a', 44); // Invalidates: - db.query_mut(ConstantsInput).set_constant('a', 66); + db.query_mut(ConstantsInputQuery).set_constant('a', 66); } /// Test that invoking `set` on a constant is an error, even if you @@ -49,54 +44,54 @@ fn invalidate_constant_1() { #[should_panic] fn set_after_constant_same_value() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set_constant('a', 44); - db.query_mut(ConstantsInput).set('a', 44); + db.query_mut(ConstantsInputQuery).set_constant('a', 44); + db.query_mut(ConstantsInputQuery).set('a', 44); } #[test] fn not_constant() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set('a', 22); - db.query_mut(ConstantsInput).set('b', 44); + db.query_mut(ConstantsInputQuery).set('a', 22); + db.query_mut(ConstantsInputQuery).set('b', 44); assert_eq!(db.constants_add(('a', 'b')), 66); - assert!(!db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(!db.query(ConstantsAddQuery).is_constant(('a', 'b'))); } #[test] fn is_constant() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set_constant('a', 22); - db.query_mut(ConstantsInput).set_constant('b', 44); + db.query_mut(ConstantsInputQuery).set_constant('a', 22); + db.query_mut(ConstantsInputQuery).set_constant('b', 44); assert_eq!(db.constants_add(('a', 'b')), 66); - assert!(db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(db.query(ConstantsAddQuery).is_constant(('a', 'b'))); } #[test] fn mixed_constant() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set_constant('a', 22); - db.query_mut(ConstantsInput).set('b', 44); + db.query_mut(ConstantsInputQuery).set_constant('a', 22); + db.query_mut(ConstantsInputQuery).set('b', 44); assert_eq!(db.constants_add(('a', 'b')), 66); - assert!(!db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(!db.query(ConstantsAddQuery).is_constant(('a', 'b'))); } #[test] fn becomes_constant_with_change() { let db = &mut TestContextImpl::default(); - db.query_mut(ConstantsInput).set('a', 22); - db.query_mut(ConstantsInput).set('b', 44); + db.query_mut(ConstantsInputQuery).set('a', 22); + db.query_mut(ConstantsInputQuery).set('b', 44); assert_eq!(db.constants_add(('a', 'b')), 66); - assert!(!db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(!db.query(ConstantsAddQuery).is_constant(('a', 'b'))); - db.query_mut(ConstantsInput).set_constant('a', 23); + db.query_mut(ConstantsInputQuery).set_constant('a', 23); assert_eq!(db.constants_add(('a', 'b')), 67); - assert!(!db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(!db.query(ConstantsAddQuery).is_constant(('a', 'b'))); - db.query_mut(ConstantsInput).set_constant('b', 45); + db.query_mut(ConstantsInputQuery).set_constant('b', 45); assert_eq!(db.constants_add(('a', 'b')), 68); - assert!(db.query(ConstantsAdd).is_constant(('a', 'b'))); + assert!(db.query(ConstantsAddQuery).is_constant(('a', 'b'))); } diff --git a/tests/incremental/implementation.rs b/tests/incremental/implementation.rs index df3a2f6d..d9dad5d6 100644 --- a/tests/incremental/implementation.rs +++ b/tests/incremental/implementation.rs @@ -41,28 +41,28 @@ impl TestContextImpl { salsa::database_storage! { pub(crate) struct TestContextImplStorage for TestContextImpl { impl constants::ConstantsDatabase { - fn constants_input() for constants::ConstantsInput; - fn constants_derived() for constants::ConstantsAdd; + fn constants_input() for constants::ConstantsInputQuery; + fn constants_derived() for constants::ConstantsAddQuery; } impl memoized_dep_inputs::MemoizedDepInputsContext { - fn dep_memoized2() for memoized_dep_inputs::Memoized2; - fn dep_memoized1() for memoized_dep_inputs::Memoized1; - fn dep_derived1() for memoized_dep_inputs::Derived1; - fn dep_input1() for memoized_dep_inputs::Input1; - fn dep_input2() for memoized_dep_inputs::Input2; + fn dep_memoized2() for memoized_dep_inputs::DepMemoized2Query; + fn dep_memoized1() for memoized_dep_inputs::DepMemoized1Query; + fn dep_derived1() for memoized_dep_inputs::DepDerived1Query; + fn dep_input1() for memoized_dep_inputs::DepInput1Query; + fn dep_input2() for memoized_dep_inputs::DepInput2Query; } impl memoized_inputs::MemoizedInputsContext { - fn max() for memoized_inputs::Max; - fn input1() for memoized_inputs::Input1; - fn input2() for memoized_inputs::Input2; + fn max() for memoized_inputs::MaxQuery; + fn input1() for memoized_inputs::Input1Query; + fn input2() for memoized_inputs::Input2Query; } impl memoized_volatile::MemoizedVolatileContext { - fn memoized2() for memoized_volatile::Memoized2; - fn memoized1() for memoized_volatile::Memoized1; - fn volatile() for memoized_volatile::Volatile; + fn memoized2() for memoized_volatile::Memoized2Query; + fn memoized1() for memoized_volatile::Memoized1Query; + fn volatile() for memoized_volatile::VolatileQuery; } } } diff --git a/tests/incremental/memoized_dep_inputs.rs b/tests/incremental/memoized_dep_inputs.rs index ac895845..ad89aa58 100644 --- a/tests/incremental/memoized_dep_inputs.rs +++ b/tests/incremental/memoized_dep_inputs.rs @@ -1,27 +1,16 @@ use crate::implementation::{TestContext, TestContextImpl}; use salsa::Database; -salsa::query_group! { - pub(crate) trait MemoizedDepInputsContext: TestContext { - fn dep_memoized2() -> usize { - type Memoized2; - } - fn dep_memoized1() -> usize { - type Memoized1; - } - fn dep_derived1() -> usize { - type Derived1; - storage dependencies; - } - fn dep_input1() -> usize { - type Input1; - storage input; - } - fn dep_input2() -> usize { - type Input2; - storage input; - } - } +#[salsa::query_group] +pub(crate) trait MemoizedDepInputsContext: TestContext { + fn dep_memoized2(&self) -> usize; + fn dep_memoized1(&self) -> usize; + #[salsa::dependencies] + fn dep_derived1(&self) -> usize; + #[salsa::input] + fn dep_input1(&self) -> usize; + #[salsa::input] + fn dep_input2(&self) -> usize; } fn dep_memoized2(db: &impl MemoizedDepInputsContext) -> usize { @@ -43,7 +32,7 @@ fn dep_derived1(db: &impl MemoizedDepInputsContext) -> usize { fn revalidate() { let db = &mut TestContextImpl::default(); - db.query_mut(Input1).set((), 0); + db.query_mut(DepInput1Query).set((), 0); // Initial run starts from Memoized2: let v = db.dep_memoized2(); @@ -53,19 +42,19 @@ fn revalidate() { // After that, we first try to validate Memoized1 but wind up // running Memoized2. Note that we don't try to validate // Derived1, so it is invoked by Memoized1. - db.query_mut(Input1).set((), 44); + db.query_mut(DepInput1Query).set((), 44); let v = db.dep_memoized2(); assert_eq!(v, 44); db.assert_log(&["Memoized1 invoked", "Derived1 invoked", "Memoized2 invoked"]); // Here validation of Memoized1 succeeds so Memoized2 never runs. - db.query_mut(Input1).set((), 45); + db.query_mut(DepInput1Query).set((), 45); let v = db.dep_memoized2(); assert_eq!(v, 44); db.assert_log(&["Memoized1 invoked", "Derived1 invoked"]); // Here, a change to input2 doesn't affect us, so nothing runs. - db.query_mut(Input2).set((), 45); + db.query_mut(DepInput2Query).set((), 45); let v = db.dep_memoized2(); assert_eq!(v, 44); db.assert_log(&[]); diff --git a/tests/incremental/memoized_inputs.rs b/tests/incremental/memoized_inputs.rs index 7957144e..0fdd65b4 100644 --- a/tests/incremental/memoized_inputs.rs +++ b/tests/incremental/memoized_inputs.rs @@ -1,20 +1,13 @@ use crate::implementation::{TestContext, TestContextImpl}; use salsa::Database; -salsa::query_group! { - pub(crate) trait MemoizedInputsContext: TestContext { - fn max() -> usize { - type Max; - } - fn input1() -> usize { - type Input1; - storage input; - } - fn input2() -> usize { - type Input2; - storage input; - } - } +#[salsa::query_group] +pub(crate) trait MemoizedInputsContext: TestContext { + fn max(&self) -> usize; + #[salsa::input] + fn input1(&self) -> usize; + #[salsa::input] + fn input2(&self) -> usize; } fn max(db: &impl MemoizedInputsContext) -> usize { @@ -26,8 +19,8 @@ fn max(db: &impl MemoizedInputsContext) -> usize { fn revalidate() { let db = &mut TestContextImpl::default(); - db.query_mut(Input1).set((), 0); - db.query_mut(Input2).set((), 0); + db.query_mut(Input1Query).set((), 0); + db.query_mut(Input2Query).set((), 0); let v = db.max(); assert_eq!(v, 0); @@ -37,7 +30,7 @@ fn revalidate() { assert_eq!(v, 0); db.assert_log(&[]); - db.query_mut(Input1).set((), 44); + db.query_mut(Input1Query).set((), 44); db.assert_log(&[]); let v = db.max(); @@ -48,11 +41,11 @@ fn revalidate() { assert_eq!(v, 44); db.assert_log(&[]); - db.query_mut(Input1).set((), 44); + db.query_mut(Input1Query).set((), 44); db.assert_log(&[]); - db.query_mut(Input2).set((), 66); + db.query_mut(Input2Query).set((), 66); db.assert_log(&[]); - db.query_mut(Input1).set((), 64); + db.query_mut(Input1Query).set((), 64); db.assert_log(&[]); let v = db.max(); @@ -70,14 +63,14 @@ fn revalidate() { fn set_after_no_change() { let db = &mut TestContextImpl::default(); - db.query_mut(Input2).set((), 0); + db.query_mut(Input2Query).set((), 0); - db.query_mut(Input1).set((), 44); + db.query_mut(Input1Query).set((), 44); let v = db.max(); assert_eq!(v, 44); db.assert_log(&["Max invoked"]); - db.query_mut(Input1).set((), 44); + db.query_mut(Input1Query).set((), 44); let v = db.max(); assert_eq!(v, 44); db.assert_log(&["Max invoked"]); diff --git a/tests/incremental/memoized_volatile.rs b/tests/incremental/memoized_volatile.rs index 0385dfc4..69f3f7d8 100644 --- a/tests/incremental/memoized_volatile.rs +++ b/tests/incremental/memoized_volatile.rs @@ -1,21 +1,14 @@ use crate::implementation::{TestContext, TestContextImpl}; use salsa::Database; -salsa::query_group! { - pub(crate) trait MemoizedVolatileContext: TestContext { - // Queries for testing a "volatile" value wrapped by - // memoization. - fn memoized2() -> usize { - type Memoized2; - } - fn memoized1() -> usize { - type Memoized1; - } - fn volatile() -> usize { - type Volatile; - storage volatile; - } - } +#[salsa::query_group] +pub(crate) trait MemoizedVolatileContext: TestContext { + // Queries for testing a "volatile" value wrapped by + // memoization. + fn memoized2(&self) -> usize; + fn memoized1(&self) -> usize; + #[salsa::volatile] + fn volatile(&self) -> usize; } fn memoized2(db: &impl MemoizedVolatileContext) -> usize { diff --git a/tests/macros.rs b/tests/macros.rs index 62daace7..86458094 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,10 +1,7 @@ -salsa::query_group! { - trait MyDatabase: salsa::Database { - fn my_query(key: ()) -> () { - type MyQuery; - use fn another_module::another_name; - } - } +#[salsa::query_group] +trait MyDatabase: salsa::Database { + #[salsa::invoke(another_module::another_name)] + fn my_query(&self, key: ()) -> (); } mod another_module { diff --git a/tests/panic_safely.rs b/tests/panic_safely.rs index c06b59c4..01d00d47 100644 --- a/tests/panic_safely.rs +++ b/tests/panic_safely.rs @@ -1,17 +1,12 @@ use salsa::{Database, ParallelDatabase, Snapshot}; use std::panic::{self, AssertUnwindSafe}; -salsa::query_group! { - trait PanicSafelyDatabase: salsa::Database { - fn one() -> usize { - type One; - storage input; - } +#[salsa::query_group] +trait PanicSafelyDatabase: salsa::Database { + #[salsa::input] + fn one(&self) -> usize; - fn panic_safely() -> () { - type PanicSafely; - } - } + fn panic_safely(&self) -> (); } fn panic_safely(db: &impl PanicSafelyDatabase) -> () { @@ -40,8 +35,8 @@ impl salsa::ParallelDatabase for DatabaseStruct { salsa::database_storage! { struct DatabaseStorage for DatabaseStruct { impl PanicSafelyDatabase { - fn one() for One; - fn panic_safely() for PanicSafely; + fn one() for OneQuery; + fn panic_safely() for PanicSafelyQuery; } } } @@ -59,7 +54,7 @@ fn should_panic_safely() { assert!(result.is_err()); // Set `db.one` to 1 and assert ok - db.query_mut(One).set((), 1); + db.query_mut(OneQuery).set((), 1); let result = panic::catch_unwind(AssertUnwindSafe(|| db.panic_safely())); assert!(result.is_ok()) } diff --git a/tests/parallel/cancellation.rs b/tests/parallel/cancellation.rs index 8efb7f2b..0789945d 100644 --- a/tests/parallel/cancellation.rs +++ b/tests/parallel/cancellation.rs @@ -1,5 +1,5 @@ use crate::setup::{ - CancelationFlag, Canceled, Input, Knobs, ParDatabase, ParDatabaseImpl, WithValue, + CancelationFlag, Canceled, InputQuery, Knobs, ParDatabase, ParDatabaseImpl, WithValue, }; use salsa::{Database, ParallelDatabase}; @@ -34,10 +34,10 @@ fn in_par_get_set_cancellation_immediate() { check_cancelation(|flag| { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); - db.query_mut(Input).set('d', 0); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); + db.query_mut(InputQuery).set('d', 0); let thread1 = std::thread::spawn({ let db = db.snapshot(); @@ -56,7 +56,7 @@ fn in_par_get_set_cancellation_immediate() { db.wait_for(1); // Try to set the input. This will signal cancellation. - db.query_mut(Input).set('d', 1000); + db.query_mut(InputQuery).set('d', 1000); // This should re-compute the value (even though no input has changed). let thread2 = std::thread::spawn({ @@ -77,10 +77,10 @@ fn in_par_get_set_cancellation_transitive() { check_cancelation(|flag| { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); - db.query_mut(Input).set('d', 0); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); + db.query_mut(InputQuery).set('d', 0); let thread1 = std::thread::spawn({ let db = db.snapshot(); @@ -99,7 +99,7 @@ fn in_par_get_set_cancellation_transitive() { db.wait_for(1); // Try to set the input. This will signal cancellation. - db.query_mut(Input).set('d', 1000); + db.query_mut(InputQuery).set('d', 1000); // This should re-compute the value (even though no input has changed). let thread2 = std::thread::spawn({ @@ -119,7 +119,7 @@ fn no_back_dating_in_cancellation() { check_cancelation(|flag| { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 1); + db.query_mut(InputQuery).set('a', 1); let thread1 = std::thread::spawn({ let db = db.snapshot(); move || { @@ -136,7 +136,7 @@ fn no_back_dating_in_cancellation() { db.wait_for(1); // Set unrelated input to bump revision - db.query_mut(Input).set('b', 2); + db.query_mut(InputQuery).set('b', 2); // Here we should recompuet the whole chain again, clearing the cancellation // state. If we get `usize::max()` here, it is a bug! @@ -144,8 +144,8 @@ fn no_back_dating_in_cancellation() { assert_canceled!(flag, thread1); - db.query_mut(Input).set('a', 3); - db.query_mut(Input).set('a', 4); + db.query_mut(InputQuery).set('a', 3); + db.query_mut(InputQuery).set('a', 4); assert_eq!(db.sum3("ab"), 6); }) } @@ -160,7 +160,7 @@ fn no_back_dating_in_cancellation() { fn transitive_cancellation() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 1); + db.query_mut(InputQuery).set('a', 1); let thread1 = std::thread::spawn({ let db = db.snapshot(); move || { @@ -176,7 +176,7 @@ fn transitive_cancellation() { db.wait_for(1); - db.query_mut(Input).set('b', 2); + db.query_mut(InputQuery).set('b', 2); // Check that when we call `sum3_drop_sum` we don't wind up having // to actually re-execute it, because the result of `sum2` winds diff --git a/tests/parallel/frozen.rs b/tests/parallel/frozen.rs index 9a830af3..4a1618c7 100644 --- a/tests/parallel/frozen.rs +++ b/tests/parallel/frozen.rs @@ -1,4 +1,4 @@ -use crate::setup::{Input, ParDatabase, ParDatabaseImpl}; +use crate::setup::{InputQuery, ParDatabase, ParDatabaseImpl}; use crate::signal::Signal; use salsa::{Database, ParallelDatabase}; use std::sync::Arc; @@ -10,7 +10,7 @@ use std::sync::Arc; fn in_par_get_set_cancellation() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 1); + db.query_mut(InputQuery).set('a', 1); let signal = Arc::new(Signal::default()); @@ -50,7 +50,7 @@ fn in_par_get_set_cancellation() { signal.wait_for(1); // This will block until thread1 drops the revision lock. - db.query_mut(Input).set('a', 2); + db.query_mut(InputQuery).set('a', 2); db.input('a') } diff --git a/tests/parallel/independent.rs b/tests/parallel/independent.rs index 252b15db..328c6711 100644 --- a/tests/parallel/independent.rs +++ b/tests/parallel/independent.rs @@ -1,4 +1,4 @@ -use crate::setup::{Input, ParDatabase, ParDatabaseImpl}; +use crate::setup::{InputQuery, ParDatabase, ParDatabaseImpl}; use salsa::{Database, ParallelDatabase}; /// Test two `sum` queries (on distinct keys) executing in different @@ -7,12 +7,12 @@ use salsa::{Database, ParallelDatabase}; fn in_par_two_independent_queries() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); - db.query_mut(Input).set('d', 200); - db.query_mut(Input).set('e', 020); - db.query_mut(Input).set('f', 002); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); + db.query_mut(InputQuery).set('d', 200); + db.query_mut(InputQuery).set('e', 020); + db.query_mut(InputQuery).set('f', 002); let thread1 = std::thread::spawn({ let db = db.snapshot(); diff --git a/tests/parallel/race.rs b/tests/parallel/race.rs index 234aea8e..bf7238d1 100644 --- a/tests/parallel/race.rs +++ b/tests/parallel/race.rs @@ -1,4 +1,4 @@ -use crate::setup::{Input, ParDatabase, ParDatabaseImpl}; +use crate::setup::{InputQuery, ParDatabase, ParDatabaseImpl}; use salsa::{Database, ParallelDatabase}; /// Test where a read and a set are racing with one another. @@ -7,9 +7,9 @@ use salsa::{Database, ParallelDatabase}; fn in_par_get_set_race() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); let thread1 = std::thread::spawn({ let db = db.snapshot(); @@ -20,7 +20,7 @@ fn in_par_get_set_race() { }); let thread2 = std::thread::spawn(move || { - db.query_mut(Input).set('a', 1000); + db.query_mut(InputQuery).set('a', 1000); db.sum("a") }); diff --git a/tests/parallel/setup.rs b/tests/parallel/setup.rs index f7170797..99549034 100644 --- a/tests/parallel/setup.rs +++ b/tests/parallel/setup.rs @@ -5,41 +5,26 @@ use salsa::Snapshot; use std::cell::Cell; use std::sync::Arc; -salsa::query_group! { - pub(crate) trait ParDatabase: Knobs + salsa::ParallelDatabase { - fn input(key: char) -> usize { - type Input; - storage input; - } +#[salsa::query_group] +pub(crate) trait ParDatabase: Knobs + salsa::ParallelDatabase { + #[salsa::input] + fn input(&self, key: char) -> usize; - fn sum(key: &'static str) -> usize { - type Sum; - } + fn sum(&self, key: &'static str) -> usize; - /// Invokes `sum` - fn sum2(key: &'static str) -> usize { - type Sum2; - } + /// Invokes `sum` + fn sum2(&self, key: &'static str) -> usize; - /// Invokes `sum` but doesn't really care about the result. - fn sum2_drop_sum(key: &'static str) -> usize { - type Sum2Drop; - } + /// Invokes `sum` but doesn't really care about the result. + fn sum2_drop_sum(&self, key: &'static str) -> usize; - /// Invokes `sum2` - fn sum3(key: &'static str) -> usize { - type Sum3; - } + /// Invokes `sum2` + fn sum3(&self, key: &'static str) -> usize; - /// Invokes `sum2_drop_sum` - fn sum3_drop_sum(key: &'static str) -> usize { - type Sum3Drop; - } + /// Invokes `sum2_drop_sum` + fn sum3_drop_sum(&self, key: &'static str) -> usize; - fn snapshot_me() -> () { - type SnapshotMe; - } - } + fn snapshot_me(&self) -> (); } #[derive(PartialEq, Eq)] @@ -252,13 +237,13 @@ impl Knobs for ParDatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for ParDatabaseImpl { impl ParDatabase { - fn input() for Input; - fn sum() for Sum; - fn sum2() for Sum2; - fn sum2_drop_sum() for Sum2Drop; - fn sum3() for Sum3; - fn sum3_drop_sum() for Sum3Drop; - fn snapshot_me() for SnapshotMe; + fn input() for InputQuery; + fn sum() for SumQuery; + fn sum2() for Sum2Query; + fn sum2_drop_sum() for Sum2DropSumQuery; + fn sum3() for Sum3Query; + fn sum3_drop_sum() for Sum3DropSumQuery; + fn snapshot_me() for SnapshotMeQuery; } } } diff --git a/tests/parallel/stress.rs b/tests/parallel/stress.rs index 440e4bbc..aa93e431 100644 --- a/tests/parallel/stress.rs +++ b/tests/parallel/stress.rs @@ -12,21 +12,14 @@ const N_READER_OPS: usize = 100; struct Canceled; type Cancelable = Result; -salsa::query_group! { - trait StressDatabase: salsa::Database { - fn a(key: usize) -> usize { - type A; - storage input; - } +#[salsa::query_group] +trait StressDatabase: salsa::Database { + #[salsa::input] + fn a(&self, key: usize) -> usize; - fn b(key: usize) -> Cancelable { - type B; - } + fn b(&self, key: usize) -> Cancelable; - fn c(key: usize) -> Cancelable { - type C; - } - } + fn c(&self, key: usize) -> Cancelable; } fn b(db: &impl StressDatabase, key: usize) -> Cancelable { @@ -62,9 +55,9 @@ impl salsa::ParallelDatabase for StressDatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for StressDatabaseImpl { impl StressDatabase { - fn a() for A; - fn b() for B; - fn c() for C; + fn a() for AQuery; + fn b() for BQuery; + fn c() for CQuery; } } } @@ -157,7 +150,7 @@ impl WriteOp { fn execute(self, db: &mut StressDatabaseImpl) { match self { WriteOp::SetA(key, value) => { - db.query_mut(A).set(key, value); + db.query_mut(AQuery).set(key, value); } } } @@ -179,13 +172,13 @@ impl ReadOp { }, ReadOp::Gc(query, strategy) => match query { Query::A => { - db.query(A).sweep(strategy); + db.query(AQuery).sweep(strategy); } Query::B => { - db.query(B).sweep(strategy); + db.query(BQuery).sweep(strategy); } Query::C => { - db.query(C).sweep(strategy); + db.query(CQuery).sweep(strategy); } }, ReadOp::GcAll(strategy) => { @@ -199,7 +192,7 @@ impl ReadOp { fn stress_test() { let mut db = StressDatabaseImpl::default(); for i in 0..10 { - db.query_mut(A).set(i, i); + db.query_mut(AQuery).set(i, i); } let mut rng = rand::thread_rng(); diff --git a/tests/parallel/true_parallel.rs b/tests/parallel/true_parallel.rs index 18ed3dd7..b0b44afd 100644 --- a/tests/parallel/true_parallel.rs +++ b/tests/parallel/true_parallel.rs @@ -1,4 +1,4 @@ -use crate::setup::{Input, Knobs, ParDatabase, ParDatabaseImpl, WithValue}; +use crate::setup::{InputQuery, Knobs, ParDatabase, ParDatabaseImpl, WithValue}; use salsa::{Database, ParallelDatabase}; use std::panic::{self, AssertUnwindSafe}; @@ -10,9 +10,9 @@ use std::panic::{self, AssertUnwindSafe}; fn true_parallel_different_keys() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); // Thread 1 will signal stage 1 when it enters and wait for stage 2. let thread1 = std::thread::spawn({ @@ -50,9 +50,9 @@ fn true_parallel_different_keys() { fn true_parallel_same_keys() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 100); - db.query_mut(Input).set('b', 010); - db.query_mut(Input).set('c', 001); + db.query_mut(InputQuery).set('a', 100); + db.query_mut(InputQuery).set('b', 010); + db.query_mut(InputQuery).set('c', 001); // Thread 1 will wait_for a barrier in the start of `sum` let thread1 = std::thread::spawn({ @@ -91,7 +91,7 @@ fn true_parallel_same_keys() { fn true_parallel_propagate_panic() { let mut db = ParDatabaseImpl::default(); - db.query_mut(Input).set('a', 1); + db.query_mut(InputQuery).set('a', 1); // `thread1` will wait_for a barrier in the start of `sum`. Once it can // continue, it will panic. diff --git a/tests/set_unchecked.rs b/tests/set_unchecked.rs index 4a308883..4147f29a 100644 --- a/tests/set_unchecked.rs +++ b/tests/set_unchecked.rs @@ -1,20 +1,13 @@ use salsa::Database; -salsa::query_group! { - trait HelloWorldDatabase: salsa::Database { - fn input() -> String { - type Input; - storage input; - } +#[salsa::query_group] +trait HelloWorldDatabase: salsa::Database { + #[salsa::input] + fn input(&self) -> String; - fn length() -> usize { - type Length; - } + fn length(&self) -> usize; - fn double_length() -> usize { - type DoubleLength; - } - } + fn double_length(&self) -> usize; } fn length(db: &impl HelloWorldDatabase) -> usize { @@ -41,9 +34,9 @@ impl salsa::Database for DatabaseStruct { salsa::database_storage! { struct DatabaseStorage for DatabaseStruct { impl HelloWorldDatabase { - fn input() for Input; - fn length() for Length; - fn double_length() for DoubleLength; + fn input() for InputQuery; + fn length() for LengthQuery; + fn double_length() for DoubleLengthQuery; } } } @@ -51,9 +44,9 @@ salsa::database_storage! { #[test] fn normal() { let mut db = DatabaseStruct::default(); - db.query_mut(Input).set((), format!("Hello, world")); + db.query_mut(InputQuery).set((), format!("Hello, world")); assert_eq!(db.double_length(), 24); - db.query_mut(Input).set((), format!("Hello, world!")); + db.query_mut(InputQuery).set((), format!("Hello, world!")); assert_eq!(db.double_length(), 26); } @@ -67,7 +60,7 @@ fn use_without_set() { #[test] fn using_set_unchecked_on_input() { let mut db = DatabaseStruct::default(); - db.query_mut(Input) + db.query_mut(InputQuery) .set_unchecked((), format!("Hello, world")); assert_eq!(db.double_length(), 24); } @@ -75,12 +68,12 @@ fn using_set_unchecked_on_input() { #[test] fn using_set_unchecked_on_input_after() { let mut db = DatabaseStruct::default(); - db.query_mut(Input).set((), format!("Hello, world")); + db.query_mut(InputQuery).set((), format!("Hello, world")); assert_eq!(db.double_length(), 24); // If we use `set_unchecked`, we don't notice that `double_length` // is out of date. Oh well, don't do that. - db.query_mut(Input) + db.query_mut(InputQuery) .set_unchecked((), format!("Hello, world!")); assert_eq!(db.double_length(), 24); } @@ -91,7 +84,7 @@ fn using_set_unchecked() { // Use `set_unchecked` to intentionally set the wrong value, // demonstrating that the code never runs. - db.query_mut(Length).set_unchecked((), 24); + db.query_mut(LengthQuery).set_unchecked((), 24); assert_eq!(db.double_length(), 48); } diff --git a/tests/storage_varieties/implementation.rs b/tests/storage_varieties/implementation.rs index 5bcb6eb1..a6e56ab8 100644 --- a/tests/storage_varieties/implementation.rs +++ b/tests/storage_varieties/implementation.rs @@ -10,8 +10,8 @@ pub struct DatabaseImpl { salsa::database_storage! { pub struct DatabaseImplStorage for DatabaseImpl { impl queries::Database { - fn memoized() for queries::Memoized; - fn volatile() for queries::Volatile; + fn memoized() for queries::MemoizedQuery; + fn volatile() for queries::VolatileQuery; } } } diff --git a/tests/storage_varieties/queries.rs b/tests/storage_varieties/queries.rs index 89cfaedf..18ccd2b7 100644 --- a/tests/storage_varieties/queries.rs +++ b/tests/storage_varieties/queries.rs @@ -2,16 +2,11 @@ pub(crate) trait Counter: salsa::Database { fn increment(&self) -> usize; } -salsa::query_group! { - pub(crate) trait Database: Counter { - fn memoized() -> usize { - type Memoized; - } - fn volatile() -> usize { - type Volatile; - storage volatile; - } - } +#[salsa::query_group] +pub(crate) trait Database: Counter { + fn memoized(&self) -> usize; + #[salsa::volatile] + fn volatile(&self) -> usize; } /// Because this query is memoized, we only increment the counter diff --git a/tests/variadic.rs b/tests/variadic.rs index 6b17697f..8ac3e042 100644 --- a/tests/variadic.rs +++ b/tests/variadic.rs @@ -1,28 +1,17 @@ use salsa::Database; -salsa::query_group! { - trait HelloWorldDatabase: salsa::Database { - fn input(a: u32, b: u32) -> u32 { - type Input; - storage input; - } +#[salsa::query_group] +trait HelloWorldDatabase: salsa::Database { + #[salsa::input] + fn input(&self, a: u32, b: u32) -> u32; - fn none() -> u32 { - type None; - } + fn none(&self) -> u32; - fn one(k: u32) -> u32 { - type One; - } + fn one(&self, k: u32) -> u32; - fn two(a: u32, b: u32) -> u32 { - type Two; - } + fn two(&self, a: u32, b: u32) -> u32; - fn trailing(a: u32, b: u32,) -> u32 { - type Trailing; - } - } + fn trailing(&self, a: u32, b: u32) -> u32; } fn none(_db: &impl HelloWorldDatabase) -> u32 { @@ -55,11 +44,11 @@ impl salsa::Database for DatabaseStruct { salsa::database_storage! { struct DatabaseStorage for DatabaseStruct { impl HelloWorldDatabase { - fn input() for Input; - fn none() for None; - fn one() for One; - fn two() for Two; - fn trailing() for Trailing; + fn input() for InputQuery; + fn none() for NoneQuery; + fn one() for OneQuery; + fn two() for TwoQuery; + fn trailing() for TrailingQuery; } } } @@ -69,7 +58,7 @@ fn execute() { let mut db = DatabaseStruct::default(); // test what happens with inputs: - db.query_mut(Input).set((1, 2), 3); + db.query_mut(InputQuery).set((1, 2), 3); assert_eq!(db.input(1, 2), 3); assert_eq!(db.none(), 22);