diff --git a/src/lib.rs b/src/lib.rs index 471688b..66c44bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ use std::hash::Hash; pub mod dyn_descriptor; pub mod memoized; +pub mod transparent; pub trait BaseQueryContext: Sized { /// A "query descriptor" packages up all the possible queries and a key. @@ -167,13 +168,79 @@ macro_rules! query_prototype { /// trait. #[macro_export] macro_rules! query_definition { + // Step 1. Filtering the attributes to look for the special ones + // we consume. ( - $(#[$attr:meta])* - $v:vis $name:ident($query:tt : &impl $query_trait:path, $key:tt : $key_ty:ty) -> $value_ty:ty { - $($body:tt)* + @filter_attrs { + input { #[storage(memoized)] $(#[$attr:meta])* }; + storage { $storage:tt }; + other_attrs { $($other_attrs:tt)* }; + tokens { $($tokens:tt)* }; + } + ) => { + $crate::query_definition! { + @filter_attrs { + input { $(#[$attr])* }; + storage { memoized }; + other_attrs { $($other_attrs)* }; + tokens { $($tokens)* }; + } + } + }; + + ( + @filter_attrs { + input { #[storage(transparent)] $(#[$attr:meta])* }; + storage { $storage:tt }; + other_attrs { $($other_attrs:tt)* }; + tokens { $($tokens:tt)* }; + } + ) => { + $crate::query_definition! { + @filter_attrs { + input { $(#[$attr])* }; + storage { transparent }; + other_attrs { $($other_attrs)* }; + tokens { $($tokens)* }; + } + } + }; + + ( + @filter_attrs { + input { #[$attr:meta] $(#[$attrs:meta])* }; + storage { $storage:tt }; + other_attrs { $($other_attrs:tt)* }; + tokens { $($tokens:tt)* }; + } + ) => { + $crate::query_definition! { + @filter_attrs { + input { $(#[$attrs])* }; + storage { $storage }; + other_attrs { $($other_attrs)* #[$attr] }; + tokens { $($tokens)* }; + } + } + }; + + ( + @filter_attrs { + input { }; + storage { $storage:tt }; + other_attrs { $($attrs:tt)* }; + tokens { + $v:vis $name:ident( + $query:tt : &impl $query_trait:path, + $key:tt : $key_ty:ty $(,)* + ) -> $value_ty:ty { + $($body:tt)* + } + }; } ) => { #[derive(Default, Debug)] + $(#[$attrs])* $v struct $name; impl $crate::Query for $name @@ -182,13 +249,38 @@ macro_rules! query_definition { { type Key = $key_ty; type Value = $value_ty; - type Storage = $crate::memoized::MemoizedStorage; + type Storage = $crate::query_definition! { @storage_ty[QC, Self, $storage] }; fn execute($query: &QC, $key: $key_ty) -> $value_ty { $($body)* } } - } + }; + + ( + @storage_ty[$QC:ident, $Self:ident, memoized] + ) => { + $crate::memoized::MemoizedStorage<$QC, $Self> + }; + + ( + @storage_ty[$QC:ident, $Self:ident, transparent] + ) => { + $crate::transparent::TransparentStorage + }; + + ( + $(#[$attr:meta])* $($tokens:tt)* + ) => { + $crate::query_definition! { + @filter_attrs { + input { $(#[$attr])* }; + storage { memoized }; + other_attrs { }; + tokens { $($tokens)* }; + } + } + }; } #[macro_export] diff --git a/src/transparent.rs b/src/transparent.rs new file mode 100644 index 0000000..c013260 --- /dev/null +++ b/src/transparent.rs @@ -0,0 +1,40 @@ +use crate::BaseQueryContext; +use crate::CycleDetected; +use crate::Query; +use crate::QueryStorageOps; +use crate::QueryTable; +use parking_lot::{RwLock, RwLockUpgradableReadGuard}; +use rustc_hash::FxHashMap; +use std::any::Any; +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Write; +use std::hash::Hash; + +// The master implementation that knits together all the queries +// contains a certain amount of boilerplate. This file aims to +// reduce that. + +#[derive(Default)] +pub struct TransparentStorage; + +impl QueryStorageOps for TransparentStorage +where + Q: Query, + QC: BaseQueryContext, +{ + fn try_fetch<'q>( + &self, + query: &'q QC, + key: &Q::Key, + descriptor: impl FnOnce() -> QC::QueryDescriptor, + ) -> Result { + // FIXME: Should we even call `execute_query_implementation` + // here? Or should we just call `Q::execute`, and maybe + // separate out the `push`/`pop` operations. + let descriptor = descriptor(); + Ok(query.execute_query_implementation::(descriptor, key)) + } +}