cosmic_freedesktop_icons/
cache.rs

1use std::collections::BTreeMap;
2use std::path::{Path, PathBuf};
3use std::sync::LazyLock;
4use std::sync::Mutex;
5use std::time::Instant;
6
7pub(crate) static CACHE: LazyLock<Cache> = LazyLock::new(Cache::default);
8type IconMap = BTreeMap<(String, u16, u16), CacheEntry>;
9type ThemeMap = BTreeMap<String, IconMap>;
10
11#[derive(Default)]
12pub(crate) struct Cache(Mutex<ThemeMap>);
13
14#[derive(Debug, Clone, PartialEq)]
15pub enum CacheEntry {
16    // We already looked for this and nothing was found, indicates we should not try to perform a lookup.
17    NotFound(Instant),
18    // We have this entry.
19    Found(PathBuf),
20    // We don't know this entry yet, indicate we should perform a lookup.
21    Unknown,
22}
23
24impl Cache {
25    pub fn clear(&self) {
26        self.0.lock().unwrap().clear();
27    }
28
29    pub fn insert<P: AsRef<Path>>(
30        &self,
31        theme: &str,
32        size: u16,
33        scale: u16,
34        icon_name: &str,
35        icon_path: &Option<P>,
36    ) {
37        let mut theme_map = self.0.lock().unwrap();
38        let entry = icon_path
39            .as_ref()
40            .map(|path| CacheEntry::Found(path.as_ref().to_path_buf()))
41            .unwrap_or(CacheEntry::NotFound(Instant::now()));
42
43        match theme_map.get_mut(theme) {
44            Some(icon_map) => {
45                icon_map.insert((icon_name.to_string(), size, scale), entry);
46            }
47            None => {
48                let mut icon_map = BTreeMap::new();
49                icon_map.insert((icon_name.to_string(), size, scale), entry);
50                theme_map.insert(theme.to_string(), icon_map);
51            }
52        }
53    }
54
55    pub fn get(&self, theme: &str, size: u16, scale: u16, icon_name: &str) -> CacheEntry {
56        let theme_map = self.0.lock().unwrap();
57
58        theme_map
59            .get(theme)
60            .map(|icon_map| icon_map.get(&(icon_name.to_string(), size, scale)))
61            .and_then(|path| path.cloned())
62            .unwrap_or(CacheEntry::Unknown)
63    }
64
65    pub fn reset_none(&self) {
66        let mut theme_map = self.0.lock().unwrap();
67
68        for (_theme_name, theme) in theme_map.iter_mut() {
69            for (_icon_data, cached_icon) in theme.iter_mut() {
70                if matches!(cached_icon, CacheEntry::NotFound(_)) {
71                    *cached_icon = CacheEntry::Unknown;
72                }
73            }
74        }
75    }
76}