1use paste::paste;
2use std::{
3 any::TypeId,
4 fmt::{self, Debug, Formatter},
5 future::Future,
6 hash::{DefaultHasher, Hash, Hasher},
7 pin::Pin,
8 sync::Arc,
9};
10
11use crate::{QueryOptions, maybe_local::MaybeLocal};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct ScopeCacheKey(u64);
15
16impl ScopeCacheKey {
17 pub fn new(fetcher_type_id: TypeId, options: &QueryOptions) -> Self {
18 let mut hasher = DefaultHasher::new();
19 fetcher_type_id.hash(&mut hasher);
20 options.hash(&mut hasher);
21 Self(hasher.finish())
22 }
23}
24
25impl Hash for ScopeCacheKey {
26 fn hash<H: Hasher>(&self, state: &mut H) {
27 self.0.hash(state);
28 }
29}
30
31#[cfg(any(
32 all(debug_assertions, feature = "devtools"),
33 feature = "devtools-always"
34))]
35#[track_caller]
36fn format_title(base: &str) -> Arc<String> {
37 let loc = std::panic::Location::caller();
38 let filepath = loc.file();
39 let file = format!(
40 "{}:{}:{}",
41 filepath
43 .split(std::path::MAIN_SEPARATOR_STR)
44 .last()
45 .unwrap_or(filepath),
46 loc.line(),
47 loc.column()
48 );
49 Arc::new(format!(
50 "{}: {}",
51 file,
52 base.trim_end_matches("::{{closure}}")
53 ))
54}
55
56pub struct QueryMarkerWithKey;
60
61pub struct QueryMarkerNoKey;
65
66macro_rules! define {
67 ([$($impl_fut_generics:tt)*], [$($impl_fn_generics:tt)*], $name:ident, $sname:literal, $sthread:literal) => {
68 #[doc = $sthread]
70 pub struct $name<K, V> {
76 query: Arc<dyn Fn(K) -> Pin<Box<dyn Future<Output = V> $($impl_fut_generics)*>> $($impl_fn_generics)*>,
77 invalidation_hierarchy_fn: Option<Arc<dyn for<'a> Fn(&'a K) -> Vec<String> $($impl_fn_generics)*>>,
78 on_invalidation: Vec<Arc<dyn for<'a> Fn(&'a K) $($impl_fn_generics)*>>,
79 on_gc: Vec<Arc<dyn for<'a> Fn(&'a K) $($impl_fn_generics)*>>,
80 fetcher_type_id: TypeId,
81 pub(crate) cache_key: ScopeCacheKey,
82 options: QueryOptions,
83 #[cfg(any(
84 all(debug_assertions, feature = "devtools"),
85 feature = "devtools-always"
86 ))]
87 title: Arc<String>,
88 }
89
90 impl<K, V> Clone for $name<K, V> {
91 fn clone(&self) -> Self {
92 Self {
93 query: self.query.clone(),
94 invalidation_hierarchy_fn: self.invalidation_hierarchy_fn.clone(),
95 on_invalidation: self.on_invalidation.clone(),
96 on_gc: self.on_gc.clone(),
97 fetcher_type_id: self.fetcher_type_id,
98 cache_key: self.cache_key,
99 options: self.options,
100 #[cfg(any(
101 all(debug_assertions, feature = "devtools"),
102 feature = "devtools-always"
103 ))]
104 title: self.title.clone(),
105 }
106 }
107 }
108
109 impl<K, V> Debug for $name<K, V> {
110 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
111 f.debug_struct(stringify!($name))
112 .field("query", &"Arc<dyn Fn(K) -> Pin<Box<dyn Future<Output = V>>")
113 .field("options", &self.options)
114 .finish()
115 }
116 }
117
118 paste! {
119 impl<K, V> $name<K, V> {
120 #[doc = $sname]
122 #[track_caller]
126 pub fn new<M>(
127 query_scope: impl [<$name Trait>]<K, V, M> $($impl_fn_generics)* + 'static,
128 ) -> Self
129 where
130 K: 'static $($impl_fn_generics)*,
131 V: 'static $($impl_fn_generics)*,
132 {
133 let options = query_scope.options().unwrap_or_default();
134 let fetcher_type_id = query_scope.fetcher_type_id();
135 Self {
136 fetcher_type_id,
137 cache_key: ScopeCacheKey::new(fetcher_type_id, &options),
138 options,
139 #[cfg(any(
140 all(debug_assertions, feature = "devtools"),
141 feature = "devtools-always"
142 ))]
143 title: query_scope.title(),
144 invalidation_hierarchy_fn: None,
145 on_invalidation: vec![],
146 on_gc: vec![],
147 query: Arc::new(move |key| Box::pin(query_scope.query(key))),
148 }
149 }
150
151 pub fn with_options(mut self, options: QueryOptions) -> Self {
155 self.options = options;
156 self
157 }
158
159 pub fn with_invalidation_link<S, I>(
196 mut self,
197 invalidation_hierarchy_fn: impl Fn(&K) -> I + 'static $($impl_fn_generics)*,
198 ) -> Self
199 where
200 I: IntoIterator<Item = S> + 'static $($impl_fn_generics)*,
201 S: Into<String> + 'static $($impl_fn_generics)*,
202 {
203 self.invalidation_hierarchy_fn = Some(Arc::new(move |key| {
204 invalidation_hierarchy_fn(key).into_iter().map(|s| s.into()).collect()
205 }));
206 self
207 }
208
209 pub fn on_invalidation(
213 mut self,
214 on_invalidation_cb: impl Fn(&K) + 'static $($impl_fn_generics)*,
215 ) -> Self {
216 self.on_invalidation.push(Arc::new(on_invalidation_cb));
217 self
218 }
219
220 pub fn on_gc(
222 mut self,
223 on_gc_cb: impl Fn(&K) + 'static $($impl_fn_generics)*,
224 ) -> Self {
225 self.on_gc.push(Arc::new(on_gc_cb));
226 self
227 }
228
229 #[cfg(any(feature = "devtools", feature = "devtools-always"))]
230 #[track_caller]
232 pub fn with_title(mut self, title: impl Into<String>) -> Self {
233 #[cfg(any(
234 all(debug_assertions, feature = "devtools"),
235 feature = "devtools-always"
236 ))]
237 {
238 self.title = format_title(&title.into());
239 }
240 self
241 }
242 }
243
244 pub trait [<$name Trait>] <K, V, M>
245 where
246 K: 'static,
247 V: 'static,
248 {
249 fn options(&self) -> Option<QueryOptions> {
250 Default::default()
251 }
252
253 fn fetcher_type_id(&self) -> TypeId;
254
255 fn cache_key(&self) -> ScopeCacheKey;
256
257 fn query(&self, key: K) -> impl Future<Output = V> $($impl_fut_generics)* + 'static;
258
259 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>>;
260
261 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>>;
262
263 fn on_gc(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>>;
264
265 #[cfg(any(
266 all(debug_assertions, feature = "devtools"),
267 feature = "devtools-always"
268 ))]
269 #[track_caller]
270 fn title(&self) -> Arc<String>;
271 }
272
273 impl<K, V, F, Fut> [<$name Trait>]<K, V, QueryMarkerWithKey> for F
274 where
275 K: 'static,
276 V: 'static,
277 F: Fn(K) -> Fut + 'static,
278 Fut: Future<Output = V> $($impl_fut_generics)* + 'static,
279 {
280
281 fn fetcher_type_id(&self) -> TypeId {
282 TypeId::of::<Self>()
283 }
284
285 fn cache_key(&self) -> ScopeCacheKey {
286 ScopeCacheKey::new(TypeId::of::<Self>(), &Default::default())
287 }
288
289 fn query(&self, key: K) -> impl Future<Output = V> $($impl_fut_generics)* + 'static {
290 self(key)
291 }
292
293 fn invalidation_prefix(&self, _key: &K) -> Option<Vec<String>> {
294 None
295 }
296
297 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
298 None
299 }
300
301 fn on_gc(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
302 None
303 }
304
305 #[cfg(any(
306 all(debug_assertions, feature = "devtools"),
307 feature = "devtools-always"
308 ))]
309 #[track_caller]
310 fn title(&self) -> Arc<String> {
311 format_title(std::any::type_name::<Self>())
312 }
313 }
314
315 impl<V, F, Fut> [<$name Trait>]<(), V, QueryMarkerNoKey> for F
316 where
317 V: 'static,
318 F: Fn() -> Fut + 'static,
319 Fut: Future<Output = V> $($impl_fut_generics)* + 'static,
320 {
321 fn fetcher_type_id(&self) -> TypeId {
322 TypeId::of::<Self>()
323 }
324
325 fn cache_key(&self) -> ScopeCacheKey {
326 ScopeCacheKey::new(TypeId::of::<Self>(), &Default::default())
327 }
328
329 fn query(&self, _key: ()) -> impl Future<Output = V> $($impl_fut_generics)* + 'static {
330 self()
331 }
332
333 fn invalidation_prefix(&self, _key: &()) -> Option<Vec<String>> {
334 None
335 }
336
337 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&()) $($impl_fn_generics)*>> {
338 None
339 }
340
341 fn on_gc(&self) -> Option<Arc<dyn Fn(&()) $($impl_fn_generics)*>> {
342 None
343 }
344
345 #[cfg(any(
346 all(debug_assertions, feature = "devtools"),
347 feature = "devtools-always"
348 ))]
349 #[track_caller]
350 fn title(&self) -> Arc<String> {
351 format_title(std::any::type_name::<Self>())
352 }
353 }
354
355 impl<K, V> [<$name Trait>]<K, V, QueryMarkerWithKey> for $name<K, V>
356 where
357 K: 'static,
358 V: 'static,
359 {
360 fn options(&self) -> Option<QueryOptions> {
361 Some(self.options)
362 }
363
364 fn fetcher_type_id(&self) -> TypeId {
365 self.fetcher_type_id
366 }
367
368 fn cache_key(&self) -> ScopeCacheKey {
369 self.cache_key
370 }
371
372 fn query(&self, key: K) -> impl Future<Output = V> $($impl_fut_generics)* + 'static {
373 (self.query)(key)
374 }
375
376 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>> {
377 if let Some(invalidation_hierarchy_fn) = &self.invalidation_hierarchy_fn {
378 Some(invalidation_hierarchy_fn(key))
379 } else {
380 None
381 }
382 }
383
384 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
385 if self.on_invalidation.is_empty() {
386 None
387 } else {
388 let callbacks = self.on_invalidation.clone();
389 Some(Arc::new(move |key| {
390 for cb in &callbacks {
391 cb(key);
392 }
393 }))
394 }
395 }
396
397 fn on_gc(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
398 if self.on_gc.is_empty() {
399 None
400 } else {
401 let callbacks = self.on_gc.clone();
402 Some(Arc::new(move |key| {
403 for cb in &callbacks {
404 cb(key);
405 }
406 }))
407 }
408 }
409
410 #[cfg(any(
411 all(debug_assertions, feature = "devtools"),
412 feature = "devtools-always"
413 ))]
414 #[track_caller]
415 fn title(&self) -> Arc<String> {
416 self.title.clone()
417 }
418 }
419
420 impl<K, V> [<$name Trait>]<K, V, QueryMarkerWithKey> for &$name<K, V>
421 where
422 K: 'static,
423 V: 'static,
424 {
425 fn options(&self) -> Option<QueryOptions> {
426 Some(self.options)
427 }
428
429 fn fetcher_type_id(&self) -> TypeId {
430 self.fetcher_type_id
431 }
432
433 fn cache_key(&self) -> ScopeCacheKey {
434 self.cache_key
435 }
436
437 fn query(&self, key: K) -> impl Future<Output = V> $($impl_fut_generics)* + 'static {
438 (self.query)(key)
439 }
440
441 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>> {
442 if let Some(invalidation_hierarchy_fn) = &self.invalidation_hierarchy_fn {
443 Some(invalidation_hierarchy_fn(key))
444 } else {
445 None
446 }
447 }
448
449 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
450 if self.on_invalidation.is_empty() {
451 None
452 } else {
453 let callbacks = self.on_invalidation.clone();
454 Some(Arc::new(move |key| {
455 for cb in &callbacks {
456 cb(key);
457 }
458 }))
459 }
460 }
461
462 fn on_gc(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
463 if self.on_gc.is_empty() {
464 None
465 } else {
466 let callbacks = self.on_gc.clone();
467 Some(Arc::new(move |key| {
468 for cb in &callbacks {
469 cb(key);
470 }
471 }))
472 }
473 }
474
475 #[cfg(any(
476 all(debug_assertions, feature = "devtools"),
477 feature = "devtools-always"
478 ))]
479 #[track_caller]
480 fn title(&self) -> Arc<String> {
481 self.title.clone()
482 }
483 }
484
485 impl<K, V, T, M> [<$name Trait>]<K, V, M> for Arc<T>
486 where
487 K: 'static,
488 V: 'static,
489 T: [<$name Trait>]<K, V, M>,
490 {
491 fn options(&self) -> Option<QueryOptions> {
492 T::options(self)
493 }
494
495 fn fetcher_type_id(&self) -> TypeId {
496 T::fetcher_type_id(self)
497 }
498
499 fn cache_key(&self) -> ScopeCacheKey {
500 T::cache_key(self)
501 }
502
503 fn query(&self, key: K) -> impl Future<Output = V> $($impl_fut_generics)* + 'static {
504 T::query(self, key)
505 }
506
507 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>> {
508 T::invalidation_prefix(self, key)
509 }
510
511 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
512 T::on_invalidation(self)
513 }
514
515 fn on_gc(&self) -> Option<Arc<dyn Fn(&K) $($impl_fn_generics)*>> {
516 T::on_gc(self)
517 }
518
519 #[cfg(any(
520 all(debug_assertions, feature = "devtools"),
521 feature = "devtools-always"
522 ))]
523 #[track_caller]
524 fn title(&self) -> Arc<String> {
525 T::title(self)
526 }
527 }
528 }
529 };
530}
531
532impl<K, V> QueryScopeLocalTrait<K, V, QueryMarkerWithKey> for QueryScope<K, V>
533where
534 K: 'static,
535 V: 'static,
536{
537 fn options(&self) -> Option<QueryOptions> {
538 Some(self.options)
539 }
540
541 fn fetcher_type_id(&self) -> TypeId {
542 self.fetcher_type_id
543 }
544
545 fn cache_key(&self) -> ScopeCacheKey {
546 self.cache_key
547 }
548
549 fn query(&self, key: K) -> impl Future<Output = V> + 'static {
550 (self.query)(key)
551 }
552
553 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>> {
554 self.invalidation_hierarchy_fn
555 .as_ref()
556 .map(|invalidation_hierarchy_fn| invalidation_hierarchy_fn(key))
557 }
558
559 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K)>> {
560 if self.on_invalidation.is_empty() {
561 None
562 } else {
563 let callbacks = self.on_invalidation.clone();
564 Some(Arc::new(move |key| {
565 for cb in &callbacks {
566 cb(key);
567 }
568 }))
569 }
570 }
571
572 fn on_gc(&self) -> Option<Arc<dyn Fn(&K)>> {
573 if self.on_gc.is_empty() {
574 None
575 } else {
576 let callbacks = self.on_gc.clone();
577 Some(Arc::new(move |key| {
578 for cb in &callbacks {
579 cb(key);
580 }
581 }))
582 }
583 }
584
585 #[cfg(any(
586 all(debug_assertions, feature = "devtools"),
587 feature = "devtools-always"
588 ))]
589 fn title(&self) -> Arc<String> {
590 self.title.clone()
591 }
592}
593
594impl<K, V> QueryScopeLocalTrait<K, V, QueryMarkerWithKey> for &QueryScope<K, V>
595where
596 K: 'static,
597 V: 'static,
598{
599 fn options(&self) -> Option<QueryOptions> {
600 Some(self.options)
601 }
602
603 fn fetcher_type_id(&self) -> TypeId {
604 self.fetcher_type_id
605 }
606
607 fn cache_key(&self) -> ScopeCacheKey {
608 self.cache_key
609 }
610
611 fn query(&self, key: K) -> impl Future<Output = V> + 'static {
612 (self.query)(key)
613 }
614
615 fn invalidation_prefix(&self, key: &K) -> Option<Vec<String>> {
616 self.invalidation_hierarchy_fn
617 .as_ref()
618 .map(|invalidation_hierarchy_fn| invalidation_hierarchy_fn(key))
619 }
620
621 fn on_invalidation(&self) -> Option<Arc<dyn Fn(&K)>> {
622 if self.on_invalidation.is_empty() {
623 None
624 } else {
625 let callbacks = self.on_invalidation.clone();
626 Some(Arc::new(move |key| {
627 for cb in &callbacks {
628 cb(key);
629 }
630 }))
631 }
632 }
633
634 fn on_gc(&self) -> Option<Arc<dyn Fn(&K)>> {
635 if self.on_gc.is_empty() {
636 None
637 } else {
638 let callbacks = self.on_gc.clone();
639 Some(Arc::new(move |key| {
640 for cb in &callbacks {
641 cb(key);
642 }
643 }))
644 }
645 }
646
647 #[cfg(any(
648 all(debug_assertions, feature = "devtools"),
649 feature = "devtools-always"
650 ))]
651 fn title(&self) -> Arc<String> {
652 self.title.clone()
653 }
654}
655
656define! { [+ Send], [+ Send + Sync], QueryScope, "QueryScope", "threadsafe" }
657define! { [], [], QueryScopeLocal, "QueryScopeLocal", "non-threadsafe" }
658
659#[derive(Debug, Clone)]
660pub(crate) struct QueryScopeInfo {
661 pub options: Option<QueryOptions>,
662 pub cache_key: ScopeCacheKey,
663 #[cfg(any(
664 all(debug_assertions, feature = "devtools"),
665 feature = "devtools-always"
666 ))]
667 pub title: Arc<String>,
668}
669
670impl QueryScopeInfo {
671 #[track_caller]
672 pub fn new<K, V, M>(query_scope: &impl QueryScopeTrait<K, V, M>) -> Self
673 where
674 K: 'static,
675 V: 'static,
676 {
677 Self {
678 options: query_scope.options(),
679 cache_key: query_scope.cache_key(),
680 #[cfg(any(
681 all(debug_assertions, feature = "devtools"),
682 feature = "devtools-always"
683 ))]
684 title: query_scope.title(),
685 }
686 }
687
688 #[track_caller]
689 pub fn new_local<K, V, M>(query_scope: &impl QueryScopeLocalTrait<K, V, M>) -> Self
690 where
691 K: 'static,
692 V: 'static,
693 {
694 Self {
695 options: query_scope.options(),
696 cache_key: query_scope.cache_key(),
697 #[cfg(any(
698 all(debug_assertions, feature = "devtools"),
699 feature = "devtools-always"
700 ))]
701 title: query_scope.title(),
702 }
703 }
704}
705
706pub(crate) struct QueryScopeQueryInfo<K> {
707 pub on_invalidation: Option<MaybeLocal<Arc<dyn Fn(&K)>>>,
708 pub on_gc: Option<MaybeLocal<Arc<dyn Fn(&K)>>>,
709 pub invalidation_prefix: Option<Vec<String>>,
710 _key_marker: std::marker::PhantomData<K>,
711}
712
713impl<K> QueryScopeQueryInfo<K>
714where
715 K: 'static,
716{
717 #[track_caller]
718 pub fn new<V, M>(query_scope: &impl QueryScopeTrait<K, V, M>, key: &K) -> Self
719 where
720 K: 'static,
721 V: 'static,
722 {
723 Self {
724 on_invalidation: query_scope
725 .on_invalidation()
726 .map(MaybeLocal::new_arc_with_key_arg_special),
727 on_gc: query_scope
728 .on_gc()
729 .map(MaybeLocal::new_arc_with_key_arg_special),
730 invalidation_prefix: query_scope.invalidation_prefix(key),
731 _key_marker: std::marker::PhantomData,
732 }
733 }
734
735 #[track_caller]
736 pub fn new_local<V, M>(query_scope: &impl QueryScopeLocalTrait<K, V, M>, key: &K) -> Self
737 where
738 V: 'static,
739 {
740 Self {
741 on_invalidation: query_scope.on_invalidation().map(MaybeLocal::new_local),
742 on_gc: query_scope.on_gc().map(MaybeLocal::new_local),
743 invalidation_prefix: query_scope.invalidation_prefix(key),
744 _key_marker: std::marker::PhantomData,
745 }
746 }
747}