[][src]Macro moore_svlog::query_group

macro_rules! query_group {
    (
        $(#[$attr:meta])* $v:vis trait $name:ident $(<$lt:lifetime>)* { $($t:tt)* }
    ) => { ... };
    (
        $(#[$attr:meta])* $v:vis trait $name:ident $(<$lt:lifetime>)* : $($t:tt)*
    ) => { ... };
    (
        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 `?`
                }
            )*
        }];
        lifetime[];
    ) => { ... };
    (
        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 `?`
                }
            )*
        }];
        lifetime[$lt:lifetime];
    ) => { ... };
    (
        @query_fn[
            storage(input);
            method_name($method_name:ident);
            fn_path();
            $($rest:tt)*
        ]
    ) => { ... };
    (
        @query_fn[
            storage(input);
            method_name($method_name:ident);
            fn_path($fn_path:path);
            $($rest:tt)*
        ]
    ) => { ... };
    (
        @query_fn[
            storage($($storage:ident)*);
            method_name($method_name:ident);
            fn_path();
            $($rest:tt)*
        ]
    ) => { ... };
    (
        @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);
            lifetime($($lts:lifetime)*);
        ]
    ) => { ... };
    (
        @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),*);
            lifetime($($lts:lifetime)*);
        ]
    ) => { ... };
    (
        attr[$($attr:tt)*];
        headers[$($headers:tt)*];
        tokens[$token:tt $($tokens:tt)*];
        $($rest:tt)*
    ) => { ... };
    (
        // Default case:
        @storage_ty[$DB:ident, $Self:ident, ]
    ) => { ... };
    (
        @storage_ty[$DB:ident, $Self:ident, memoized]
    ) => { ... };
    (
        @storage_ty[$DB:ident, $Self:ident, volatile]
    ) => { ... };
    (
        @storage_ty[$DB:ident, $Self:ident, dependencies]
    ) => { ... };
    (
        @storage_ty[$DB:ident, $Self:ident, input]
    ) => { ... };
    (
        @storage_ty[$DB:ident, $Self:ident, $storage:tt]
    ) => { ... };
}

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:

This example is not tested
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.