Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/query-group-macro/src/lib.rs')
-rw-r--r--crates/query-group-macro/src/lib.rs71
1 files changed, 67 insertions, 4 deletions
diff --git a/crates/query-group-macro/src/lib.rs b/crates/query-group-macro/src/lib.rs
index 2e2a24908e..3ade12733a 100644
--- a/crates/query-group-macro/src/lib.rs
+++ b/crates/query-group-macro/src/lib.rs
@@ -10,10 +10,13 @@ use queries::{
Queries, SetterKind, TrackedQuery, Transparent,
};
use quote::{ToTokens, format_ident, quote};
+use syn::parse::{Parse, ParseStream};
+use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::visit_mut::VisitMut;
use syn::{
- Attribute, FnArg, ItemTrait, Path, TraitItem, TraitItemFn, parse_quote, parse_quote_spanned,
+ Attribute, FnArg, ItemTrait, Path, Token, TraitItem, TraitItemFn, parse_quote,
+ parse_quote_spanned,
};
mod queries;
@@ -106,6 +109,66 @@ enum QueryKind {
Interned,
}
+#[derive(Default, Debug, Clone)]
+struct Cycle {
+ cycle_fn: Option<(syn::Ident, Path)>,
+ cycle_initial: Option<(syn::Ident, Path)>,
+ cycle_result: Option<(syn::Ident, Path)>,
+}
+
+impl Parse for Cycle {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let options = Punctuated::<Option, Token![,]>::parse_terminated(input)?;
+ let mut cycle_fn = None;
+ let mut cycle_initial = None;
+ let mut cycle_result = None;
+ for option in options {
+ let name = option.name.to_string();
+ match &*name {
+ "cycle_fn" => {
+ if cycle_fn.is_some() {
+ return Err(syn::Error::new_spanned(&option.name, "duplicate option"));
+ }
+ cycle_fn = Some((option.name, option.value));
+ }
+ "cycle_initial" => {
+ if cycle_initial.is_some() {
+ return Err(syn::Error::new_spanned(&option.name, "duplicate option"));
+ }
+ cycle_initial = Some((option.name, option.value));
+ }
+ "cycle_result" => {
+ if cycle_result.is_some() {
+ return Err(syn::Error::new_spanned(&option.name, "duplicate option"));
+ }
+ cycle_result = Some((option.name, option.value));
+ }
+ _ => {
+ return Err(syn::Error::new_spanned(
+ &option.name,
+ "unknown cycle option. Accepted values: `cycle_result`, `cycle_fn`, `cycle_initial`",
+ ));
+ }
+ }
+ }
+ return Ok(Self { cycle_fn, cycle_initial, cycle_result });
+
+ struct Option {
+ name: syn::Ident,
+ value: Path,
+ }
+
+ impl Parse for Option {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ let name = input.parse()?;
+ input.parse::<Token![=]>()?;
+ let value = input.parse()?;
+ Ok(Self { name, value })
+ }
+ }
+ }
+}
+
pub(crate) fn query_group_impl(
_args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
@@ -155,8 +218,8 @@ pub(crate) fn query_group_impl(
for SalsaAttr { name, tts, span } in salsa_attrs {
match name.as_str() {
"cycle" => {
- let path = syn::parse::<Parenthesized<Path>>(tts)?;
- cycle = Some(path.0.clone())
+ let c = syn::parse::<Parenthesized<Cycle>>(tts)?;
+ cycle = Some(c.0);
}
"input" => {
if !pat_and_tys.is_empty() {
@@ -415,7 +478,7 @@ impl<T> syn::parse::Parse for Parenthesized<T>
where
T: syn::parse::Parse,
{
- fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let content;
syn::parenthesized!(content in input);
content.parse::<T>().map(Parenthesized)