egui/cache/cache_storage.rs
1use super::CacheTrait;
2
3/// A typemap of many caches, all implemented with [`CacheTrait`].
4///
5/// You can access egui's caches via [`crate::Memory::caches`],
6/// found with [`crate::Context::memory_mut`].
7///
8/// ```
9/// use egui::cache::{CacheStorage, ComputerMut, FrameCache};
10///
11/// #[derive(Default)]
12/// struct CharCounter {}
13/// impl ComputerMut<&str, usize> for CharCounter {
14/// fn compute(&mut self, s: &str) -> usize {
15/// s.chars().count()
16/// }
17/// }
18/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
19///
20/// # let mut cache_storage = CacheStorage::default();
21/// let mut cache = cache_storage.cache::<CharCountCache<'_>>();
22/// assert_eq!(*cache.get("hello"), 5);
23/// ```
24#[derive(Default)]
25pub struct CacheStorage {
26 caches: ahash::HashMap<std::any::TypeId, Box<dyn CacheTrait>>,
27}
28
29impl CacheStorage {
30 pub fn cache<Cache: CacheTrait + Default>(&mut self) -> &mut Cache {
31 let cache = self
32 .caches
33 .entry(std::any::TypeId::of::<Cache>())
34 .or_insert_with(|| Box::<Cache>::default());
35
36 #[expect(clippy::unwrap_used)]
37 (cache.as_mut() as &mut dyn std::any::Any)
38 .downcast_mut::<Cache>()
39 .unwrap()
40 }
41
42 /// Total number of cached values
43 fn num_values(&self) -> usize {
44 self.caches.values().map(|cache| cache.len()).sum()
45 }
46
47 /// Call once per frame to evict cache.
48 pub fn update(&mut self) {
49 self.caches.retain(|_, cache| {
50 cache.update();
51 cache.len() > 0
52 });
53 }
54}
55
56impl Clone for CacheStorage {
57 fn clone(&self) -> Self {
58 // We return an empty cache that can be filled in again.
59 Self::default()
60 }
61}
62
63impl std::fmt::Debug for CacheStorage {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(
66 f,
67 "FrameCacheStorage[{} caches with {} elements]",
68 self.caches.len(),
69 self.num_values()
70 )
71 }
72}