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