]> git.proxmox.com Git - rustc.git/blame - vendor/salsa-macros/src/query_group.rs
New upstream version 1.48.0+dfsg1
[rustc.git] / vendor / salsa-macros / src / query_group.rs
CommitLineData
f035d41b
XL
1use std::convert::TryFrom;
2
3use crate::parenthesized::Parenthesized;
4use heck::CamelCase;
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::ToTokens;
f035d41b 8use syn::{
3dfed10e
XL
9 parse_macro_input, parse_quote, spanned::Spanned, Attribute, Error, FnArg, Ident, ItemTrait,
10 ReturnType, TraitItem, Type,
f035d41b
XL
11};
12
13/// Implementation for `[salsa::query_group]` decorator.
14pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream {
15 let group_struct = parse_macro_input!(args as Ident);
16 let input: ItemTrait = parse_macro_input!(input as ItemTrait);
17 // println!("args: {:#?}", args);
18 // println!("input: {:#?}", input);
19
3dfed10e 20 let input_span = input.span();
f035d41b 21 let (trait_attrs, salsa_attrs) = filter_attrs(input.attrs);
3dfed10e
XL
22 if !salsa_attrs.is_empty() {
23 return Error::new(
24 input_span,
25 format!("unsupported attributes: {:?}", salsa_attrs),
26 )
27 .to_compile_error()
28 .into();
f035d41b
XL
29 }
30
31 let trait_vis = input.vis;
32 let trait_name = input.ident;
33 let _generics = input.generics.clone();
3dfed10e 34 let dyn_db = quote! { dyn #trait_name };
f035d41b
XL
35
36 // Decompose the trait into the corresponding queries.
37 let mut queries = vec![];
38 for item in input.items {
39 match item {
40 TraitItem::Method(method) => {
41 let mut storage = QueryStorage::Memoized;
42 let mut cycle = None;
43 let mut invoke = None;
3dfed10e 44 let query_name = method.sig.ident.to_string();
f035d41b
XL
45 let mut query_type = Ident::new(
46 &format!("{}Query", method.sig.ident.to_string().to_camel_case()),
47 Span::call_site(),
48 );
49 let mut num_storages = 0;
50
51 // Extract attributes.
52 let (attrs, salsa_attrs) = filter_attrs(method.attrs);
3dfed10e 53 for SalsaAttr { name, tts, span } in salsa_attrs {
f035d41b
XL
54 match name.as_str() {
55 "memoized" => {
56 storage = QueryStorage::Memoized;
57 num_storages += 1;
58 }
59 "dependencies" => {
60 storage = QueryStorage::Dependencies;
61 num_storages += 1;
62 }
63 "input" => {
64 storage = QueryStorage::Input;
65 num_storages += 1;
66 }
67 "interned" => {
68 storage = QueryStorage::Interned;
69 num_storages += 1;
70 }
71 "cycle" => {
72 cycle = Some(parse_macro_input!(tts as Parenthesized<syn::Path>).0);
73 }
74 "invoke" => {
75 invoke = Some(parse_macro_input!(tts as Parenthesized<syn::Path>).0);
76 }
77 "query_type" => {
78 query_type = parse_macro_input!(tts as Parenthesized<Ident>).0;
79 }
80 "transparent" => {
81 storage = QueryStorage::Transparent;
82 num_storages += 1;
83 }
3dfed10e
XL
84 _ => {
85 return Error::new(span, format!("unknown salsa attribute `{}`", name))
86 .to_compile_error()
87 .into();
88 }
f035d41b
XL
89 }
90 }
91
92 // Check attribute combinations.
93 if num_storages > 1 {
3dfed10e
XL
94 return Error::new(method.sig.span(), "multiple storage attributes specified")
95 .to_compile_error()
96 .into();
f035d41b 97 }
3dfed10e
XL
98 match &invoke {
99 Some(invoke) if storage == QueryStorage::Input => {
100 return Error::new(
101 invoke.span(),
102 "#[salsa::invoke] cannot be set on #[salsa::input] queries",
103 )
104 .to_compile_error()
105 .into();
106 }
107 _ => {}
f035d41b
XL
108 }
109
110 // Extract keys.
111 let mut iter = method.sig.inputs.iter();
112 match iter.next() {
113 Some(FnArg::Receiver(sr)) if sr.mutability.is_none() => (),
3dfed10e
XL
114 _ => {
115 return Error::new(
116 method.sig.span(),
117 format!(
118 "first argument of query `{}` must be `&self`",
119 method.sig.ident,
120 ),
121 )
122 .to_compile_error()
123 .into();
124 }
f035d41b
XL
125 }
126 let mut keys: Vec<Type> = vec![];
127 for arg in iter {
128 match *arg {
129 FnArg::Typed(ref arg) => {
130 keys.push((*arg.ty).clone());
131 }
3dfed10e
XL
132 ref arg => {
133 return Error::new(
134 arg.span(),
135 format!(
136 "unsupported argument `{:?}` of `{}`",
137 arg, method.sig.ident,
138 ),
139 )
140 .to_compile_error()
141 .into();
142 }
f035d41b
XL
143 }
144 }
145
146 // Extract value.
147 let value = match method.sig.output {
148 ReturnType::Type(_, ref ty) => ty.as_ref().clone(),
3dfed10e
XL
149 ref ret => {
150 return Error::new(
151 ret.span(),
152 format!(
153 "unsupported return type `{:?}` of `{}`",
154 ret, method.sig.ident
155 ),
156 )
157 .to_compile_error()
158 .into();
159 }
f035d41b
XL
160 };
161
162 // For `#[salsa::interned]` keys, we create a "lookup key" automatically.
163 //
164 // For a query like:
165 //
166 // fn foo(&self, x: Key1, y: Key2) -> u32
167 //
168 // we would create
169 //
170 // fn lookup_foo(&self, x: u32) -> (Key1, Key2)
171 let lookup_query = if let QueryStorage::Interned = storage {
172 let lookup_query_type = Ident::new(
173 &format!(
174 "{}LookupQuery",
175 method.sig.ident.to_string().to_camel_case()
176 ),
177 Span::call_site(),
178 );
179 let lookup_fn_name = Ident::new(
180 &format!("lookup_{}", method.sig.ident.to_string()),
181 method.sig.ident.span(),
182 );
183 let keys = &keys;
184 let lookup_value: Type = parse_quote!((#(#keys),*));
185 let lookup_keys = vec![value.clone()];
186 Some(Query {
187 query_type: lookup_query_type,
3dfed10e 188 query_name: format!("lookup_{}", query_name),
f035d41b
XL
189 fn_name: lookup_fn_name,
190 attrs: vec![], // FIXME -- some automatically generated docs on this method?
191 storage: QueryStorage::InternedLookup {
192 intern_query_type: query_type.clone(),
193 },
194 keys: lookup_keys,
195 value: lookup_value,
196 invoke: None,
197 cycle: cycle.clone(),
198 })
199 } else {
200 None
201 };
202
203 queries.push(Query {
204 query_type,
3dfed10e 205 query_name,
f035d41b
XL
206 fn_name: method.sig.ident,
207 attrs,
208 storage,
209 keys,
210 value,
211 invoke,
212 cycle,
213 });
214
215 queries.extend(lookup_query);
216 }
217 _ => (),
218 }
219 }
220
f035d41b
XL
221 let group_storage = Ident::new(
222 &format!("{}GroupStorage__", trait_name.to_string()),
223 Span::call_site(),
224 );
225
226 let mut query_fn_declarations = proc_macro2::TokenStream::new();
227 let mut query_fn_definitions = proc_macro2::TokenStream::new();
f035d41b 228 let mut storage_fields = proc_macro2::TokenStream::new();
3dfed10e 229 let mut queries_with_storage = vec![];
f035d41b
XL
230 for query in &queries {
231 let key_names: &Vec<_> = &(0..query.keys.len())
232 .map(|i| Ident::new(&format!("key{}", i), Span::call_site()))
233 .collect();
234 let keys = &query.keys;
235 let value = &query.value;
236 let fn_name = &query.fn_name;
237 let qt = &query.query_type;
238 let attrs = &query.attrs;
239
240 query_fn_declarations.extend(quote! {
241 #(#attrs)*
242 fn #fn_name(&self, #(#key_names: #keys),*) -> #value;
243 });
244
245 // Special case: transparent queries don't create actual storage,
246 // just inline the definition
247 if let QueryStorage::Transparent = query.storage {
248 let invoke = query.invoke_tt();
249 query_fn_definitions.extend(quote! {
250 fn #fn_name(&self, #(#key_names: #keys),*) -> #value {
251 #invoke(self, #(#key_names),*)
252 }
253 });
254 continue;
255 }
256
3dfed10e
XL
257 queries_with_storage.push(fn_name);
258
f035d41b
XL
259 query_fn_definitions.extend(quote! {
260 fn #fn_name(&self, #(#key_names: #keys),*) -> #value {
3dfed10e
XL
261 // Create a shim to force the code to be monomorphized in the
262 // query crate. Our experiments revealed that this makes a big
263 // difference in total compilation time in rust-analyzer, though
264 // it's not totally obvious why that should be.
265 fn __shim(db: &dyn #trait_name, #(#key_names: #keys),*) -> #value {
266 salsa::plumbing::get_query_table::<#qt>(db).get((#(#key_names),*))
267 }
268 __shim(self, #(#key_names),*)
269
f035d41b
XL
270 }
271 });
272
273 // For input queries, we need `set_foo` etc
274 if let QueryStorage::Input = query.storage {
275 let set_fn_name = Ident::new(&format!("set_{}", fn_name), fn_name.span());
276 let set_with_durability_fn_name =
277 Ident::new(&format!("set_{}_with_durability", fn_name), fn_name.span());
278
279 let set_fn_docs = format!(
280 "
281 Set the value of the `{fn_name}` input.
282
283 See `{fn_name}` for details.
284
285 *Note:* Setting values will trigger cancellation
286 of any ongoing queries; this method blocks until
287 those queries have been cancelled.
288 ",
289 fn_name = fn_name
290 );
291
292 let set_constant_fn_docs = format!(
293 "
294 Set the value of the `{fn_name}` input and promise
295 that its value will never change again.
296
297 See `{fn_name}` for details.
298
299 *Note:* Setting values will trigger cancellation
300 of any ongoing queries; this method blocks until
301 those queries have been cancelled.
302 ",
303 fn_name = fn_name
304 );
305
306 query_fn_declarations.extend(quote! {
307 # [doc = #set_fn_docs]
308 fn #set_fn_name(&mut self, #(#key_names: #keys,)* value__: #value);
309
310
311 # [doc = #set_constant_fn_docs]
312 fn #set_with_durability_fn_name(&mut self, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability);
313 });
314
315 query_fn_definitions.extend(quote! {
316 fn #set_fn_name(&mut self, #(#key_names: #keys,)* value__: #value) {
3dfed10e
XL
317 fn __shim(db: &mut dyn #trait_name, #(#key_names: #keys,)* value__: #value) {
318 salsa::plumbing::get_query_table_mut::<#qt>(db).set((#(#key_names),*), value__)
319 }
320 __shim(self, #(#key_names,)* value__)
f035d41b
XL
321 }
322
323 fn #set_with_durability_fn_name(&mut self, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability) {
3dfed10e
XL
324 fn __shim(db: &mut dyn #trait_name, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability) {
325 salsa::plumbing::get_query_table_mut::<#qt>(db).set_with_durability((#(#key_names),*), value__, durability__)
326 }
327 __shim(self, #(#key_names,)* value__ ,durability__)
f035d41b
XL
328 }
329 });
330 }
331
f035d41b
XL
332 // A field for the storage struct
333 //
334 // FIXME(#120): the pub should not be necessary once we complete the transition
335 storage_fields.extend(quote! {
3dfed10e 336 pub #fn_name: std::sync::Arc<<#qt as salsa::Query>::Storage>,
f035d41b 337 });
f035d41b
XL
338 }
339
340 // Emit the trait itself.
341 let mut output = {
342 let bounds = &input.supertraits;
343 quote! {
344 #(#trait_attrs)*
3dfed10e
XL
345 #trait_vis trait #trait_name :
346 salsa::Database +
347 salsa::plumbing::HasQueryGroup<#group_struct> +
348 #bounds
349 {
f035d41b
XL
350 #query_fn_declarations
351 }
352 }
353 };
354
355 // Emit the query group struct and impl of `QueryGroup`.
356 output.extend(quote! {
357 /// Representative struct for the query group.
358 #trait_vis struct #group_struct { }
359
3dfed10e 360 impl salsa::plumbing::QueryGroup for #group_struct
f035d41b 361 {
3dfed10e
XL
362 type DynDb = #dyn_db;
363 type GroupStorage = #group_storage;
f035d41b
XL
364 }
365 });
366
367 // Emit an impl of the trait
368 output.extend({
3dfed10e 369 let bounds = input.supertraits.clone();
f035d41b 370 quote! {
3dfed10e 371 impl<DB> #trait_name for DB
f035d41b 372 where
3dfed10e
XL
373 DB: #bounds,
374 DB: salsa::Database,
375 DB: salsa::plumbing::HasQueryGroup<#group_struct>,
f035d41b
XL
376 {
377 #query_fn_definitions
378 }
379 }
380 });
381
3dfed10e
XL
382 let non_transparent_queries = || {
383 queries.iter().filter(|q| match q.storage {
384 QueryStorage::Transparent => false,
385 _ => true,
386 })
387 };
388
f035d41b 389 // Emit the query types.
3dfed10e 390 for (query, query_index) in non_transparent_queries().zip(0_u16..) {
f035d41b
XL
391 let fn_name = &query.fn_name;
392 let qt = &query.query_type;
393
f035d41b 394 let storage = match &query.storage {
3dfed10e
XL
395 QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<Self>),
396 QueryStorage::Dependencies => quote!(salsa::plumbing::DependencyStorage<Self>),
397 QueryStorage::Input => quote!(salsa::plumbing::InputStorage<Self>),
398 QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<Self>),
f035d41b 399 QueryStorage::InternedLookup { intern_query_type } => {
3dfed10e 400 quote!(salsa::plumbing::LookupInternedStorage<Self, #intern_query_type>)
f035d41b 401 }
3dfed10e 402 QueryStorage::Transparent => panic!("should have been filtered"),
f035d41b
XL
403 };
404 let keys = &query.keys;
405 let value = &query.value;
3dfed10e 406 let query_name = &query.query_name;
f035d41b
XL
407
408 // Emit the query struct and implement the Query trait on it.
409 output.extend(quote! {
410 #[derive(Default, Debug)]
411 #trait_vis struct #qt;
3dfed10e 412 });
f035d41b 413
3dfed10e
XL
414 output.extend(quote! {
415 impl #qt {
416 /// Get access to extra methods pertaining to this query. For
417 /// example, you can use this to run the GC (`sweep`) across a
418 /// single input. You can also use it to invoke this query, though
419 /// it's more common to use the trait method on the database
420 /// itself.
421 #trait_vis fn in_db(self, db: &#dyn_db) -> salsa::QueryTable<'_, Self>
422 {
423 salsa::plumbing::get_query_table::<#qt>(db)
424 }
425 }
426 });
427
428 if query.storage.supports_mut() {}
429 output.extend(quote! {
430 impl #qt {
431 /// Like `in_db`, but gives access to methods for setting the
432 /// value of an input. Not applicable to derived queries.
433 ///
434 /// # Threads, cancellation, and blocking
435 ///
436 /// Mutating the value of a query cannot be done while there are
437 /// still other queries executing. If you are using your database
438 /// within a single thread, this is not a problem: you only have
439 /// `&self` access to the database, but this method requires `&mut
440 /// self`.
441 ///
442 /// However, if you have used `snapshot` to create other threads,
443 /// then attempts to `set` will **block the current thread** until
444 /// those snapshots are dropped (usually when those threads
445 /// complete). This also implies that if you create a snapshot but
446 /// do not send it to another thread, then invoking `set` will
447 /// deadlock.
448 ///
449 /// Before blocking, the thread that is attempting to `set` will
450 /// also set a cancellation flag. In the threads operating on
451 /// snapshots, you can use the [`is_current_revision_canceled`]
452 /// method to check for this flag and bring those operations to a
453 /// close, thus allowing the `set` to succeed. Ignoring this flag
454 /// may lead to "starvation", meaning that the thread attempting
455 /// to `set` has to wait a long, long time. =)
456 ///
457 /// [`is_current_revision_canceled`]: struct.Runtime.html#method.is_current_revision_canceled
458 #trait_vis fn in_db_mut(self, db: &mut #dyn_db) -> salsa::QueryTableMut<'_, Self>
459 {
460 salsa::plumbing::get_query_table_mut::<#qt>(db)
461 }
462 }
463
464 // ANCHOR:Query_impl
465 impl salsa::Query for #qt
f035d41b
XL
466 {
467 type Key = (#(#keys),*);
468 type Value = #value;
469 type Storage = #storage;
470 type Group = #group_struct;
3dfed10e
XL
471 type GroupStorage = #group_storage;
472 type DynDb = #dyn_db;
473
474 const QUERY_INDEX: u16 = #query_index;
475
476 const QUERY_NAME: &'static str = #query_name;
f035d41b
XL
477
478 fn query_storage(
479 group_storage: &Self::GroupStorage,
480 ) -> &std::sync::Arc<Self::Storage> {
481 &group_storage.#fn_name
482 }
f035d41b 483 }
3dfed10e 484 // ANCHOR_END:Query_impl
f035d41b
XL
485 });
486
487 // Implement the QueryFunction trait for queries which need it.
488 if query.storage.needs_query_function() {
489 let span = query.fn_name.span();
490 let key_names: &Vec<_> = &(0..query.keys.len())
491 .map(|i| Ident::new(&format!("key{}", i), Span::call_site()))
492 .collect();
493 let key_pattern = if query.keys.len() == 1 {
494 quote! { #(#key_names),* }
495 } else {
496 quote! { (#(#key_names),*) }
497 };
498 let invoke = query.invoke_tt();
499
500 let recover = if let Some(cycle_recovery_fn) = &query.cycle {
501 quote! {
3dfed10e
XL
502 fn recover(db: &Self::DynDb, cycle: &[salsa::DatabaseKeyIndex], #key_pattern: &<Self as salsa::Query>::Key)
503 -> Option<<Self as salsa::Query>::Value> {
f035d41b
XL
504 Some(#cycle_recovery_fn(
505 db,
3dfed10e 506 &cycle.iter().map(|k| format!("{:?}", k.debug(db))).collect::<Vec<String>>(),
f035d41b
XL
507 #(#key_names),*
508 ))
509 }
510 }
511 } else {
512 quote! {}
513 };
514
515 output.extend(quote_spanned! {span=>
3dfed10e
XL
516 // ANCHOR:QueryFunction_impl
517 impl salsa::plumbing::QueryFunction for #qt
f035d41b 518 {
3dfed10e
XL
519 fn execute(db: &Self::DynDb, #key_pattern: <Self as salsa::Query>::Key)
520 -> <Self as salsa::Query>::Value {
f035d41b
XL
521 #invoke(db, #(#key_names),*)
522 }
523
524 #recover
525 }
3dfed10e 526 // ANCHOR_END:QueryFunction_impl
f035d41b
XL
527 });
528 }
529 }
530
3dfed10e
XL
531 let mut fmt_ops = proc_macro2::TokenStream::new();
532 for (Query { fn_name, .. }, query_index) in non_transparent_queries().zip(0_u16..) {
533 fmt_ops.extend(quote! {
534 #query_index => {
535 salsa::plumbing::QueryStorageOps::fmt_index(
536 &*self.#fn_name, db, input, fmt,
537 )
538 }
539 });
540 }
541
542 let mut maybe_changed_ops = proc_macro2::TokenStream::new();
543 for (Query { fn_name, .. }, query_index) in non_transparent_queries().zip(0_u16..) {
544 maybe_changed_ops.extend(quote! {
545 #query_index => {
546 salsa::plumbing::QueryStorageOps::maybe_changed_since(
547 &*self.#fn_name, db, input, revision
548 )
549 }
550 });
551 }
f035d41b
XL
552
553 let mut for_each_ops = proc_macro2::TokenStream::new();
3dfed10e 554 for Query { fn_name, .. } in non_transparent_queries() {
f035d41b
XL
555 for_each_ops.extend(quote! {
556 op(&*self.#fn_name);
557 });
558 }
559
560 // Emit query group storage struct
f035d41b 561 output.extend(quote! {
3dfed10e 562 #trait_vis struct #group_storage {
f035d41b
XL
563 #storage_fields
564 }
565
3dfed10e
XL
566 // ANCHOR:group_storage_new
567 impl #group_storage {
568 #trait_vis fn new(group_index: u16) -> Self {
f035d41b 569 #group_storage {
3dfed10e
XL
570 #(
571 #queries_with_storage:
572 std::sync::Arc::new(salsa::plumbing::QueryStorageOps::new(group_index)),
573 )*
f035d41b
XL
574 }
575 }
576 }
3dfed10e
XL
577 // ANCHOR_END:group_storage_new
578
579 // ANCHOR:group_storage_methods
580 impl #group_storage {
581 #trait_vis fn fmt_index(
582 &self,
583 db: &#dyn_db,
584 input: salsa::DatabaseKeyIndex,
585 fmt: &mut std::fmt::Formatter<'_>,
586 ) -> std::fmt::Result {
587 match input.query_index() {
588 #fmt_ops
589 i => panic!("salsa: impossible query index {}", i),
590 }
591 }
592
593 #trait_vis fn maybe_changed_since(
594 &self,
595 db: &#dyn_db,
596 input: salsa::DatabaseKeyIndex,
597 revision: salsa::Revision,
598 ) -> bool {
599 match input.query_index() {
600 #maybe_changed_ops
601 i => panic!("salsa: impossible query index {}", i),
602 }
603 }
f035d41b 604
f035d41b
XL
605 #trait_vis fn for_each_query(
606 &self,
3dfed10e
XL
607 _runtime: &salsa::Runtime,
608 mut op: &mut dyn FnMut(&dyn salsa::plumbing::QueryStorageMassOps),
f035d41b
XL
609 ) {
610 #for_each_ops
611 }
612 }
3dfed10e 613 // ANCHOR_END:group_storage_methods
f035d41b
XL
614 });
615
616 if std::env::var("SALSA_DUMP").is_ok() {
617 println!("~~~ query_group");
618 println!("{}", output.to_string());
619 println!("~~~ query_group");
620 }
621
622 output.into()
623}
624
625struct SalsaAttr {
626 name: String,
627 tts: TokenStream,
3dfed10e
XL
628 span: Span,
629}
630
631impl std::fmt::Debug for SalsaAttr {
632 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
633 write!(fmt, "{:?}", self.name)
634 }
f035d41b
XL
635}
636
637impl TryFrom<syn::Attribute> for SalsaAttr {
638 type Error = syn::Attribute;
3dfed10e 639
f035d41b
XL
640 fn try_from(attr: syn::Attribute) -> Result<SalsaAttr, syn::Attribute> {
641 if is_not_salsa_attr_path(&attr.path) {
642 return Err(attr);
643 }
644
3dfed10e 645 let span = attr.span();
f035d41b
XL
646 let name = attr.path.segments[1].ident.to_string();
647 let tts = attr.tokens.into();
3dfed10e
XL
648
649 Ok(SalsaAttr { name, tts, span })
f035d41b
XL
650 }
651}
652
653fn is_not_salsa_attr_path(path: &syn::Path) -> bool {
654 path.segments
655 .first()
656 .map(|s| s.ident != "salsa")
657 .unwrap_or(true)
658 || path.segments.len() != 2
659}
660
661fn filter_attrs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<SalsaAttr>) {
662 let mut other = vec![];
663 let mut salsa = vec![];
664 // Leave non-salsa attributes untouched. These are
665 // attributes that don't start with `salsa::` or don't have
666 // exactly two segments in their path.
667 // Keep the salsa attributes around.
668 for attr in attrs {
669 match SalsaAttr::try_from(attr) {
670 Ok(it) => salsa.push(it),
671 Err(it) => other.push(it),
672 }
673 }
674 (other, salsa)
675}
676
677#[derive(Debug)]
678struct Query {
679 fn_name: Ident,
3dfed10e 680 query_name: String,
f035d41b
XL
681 attrs: Vec<syn::Attribute>,
682 query_type: Ident,
683 storage: QueryStorage,
684 keys: Vec<syn::Type>,
685 value: syn::Type,
686 invoke: Option<syn::Path>,
687 cycle: Option<syn::Path>,
688}
689
690impl Query {
691 fn invoke_tt(&self) -> proc_macro2::TokenStream {
692 match &self.invoke {
693 Some(i) => i.into_token_stream(),
694 None => self.fn_name.clone().into_token_stream(),
695 }
696 }
697}
698
699#[derive(Debug, Clone, PartialEq, Eq)]
700enum QueryStorage {
701 Memoized,
702 Dependencies,
703 Input,
704 Interned,
705 InternedLookup { intern_query_type: Ident },
706 Transparent,
707}
708
709impl QueryStorage {
3dfed10e 710 /// Do we need a `QueryFunction` impl for this type of query?
f035d41b
XL
711 fn needs_query_function(&self) -> bool {
712 match self {
713 QueryStorage::Input
714 | QueryStorage::Interned
715 | QueryStorage::InternedLookup { .. }
716 | QueryStorage::Transparent => false,
717 QueryStorage::Memoized | QueryStorage::Dependencies => true,
718 }
719 }
3dfed10e
XL
720
721 /// Does this type of query support `&mut` operations?
722 fn supports_mut(&self) -> bool {
723 match self {
724 QueryStorage::Input => true,
725 QueryStorage::Interned
726 | QueryStorage::InternedLookup { .. }
727 | QueryStorage::Transparent
728 | QueryStorage::Memoized
729 | QueryStorage::Dependencies => false,
730 }
731 }
f035d41b 732}