From 09a76900a64f288c998f57f988470a13ad5a0dfa Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Wed, 2 Apr 2025 17:21:11 +0200 Subject: [PATCH] feat: resettable cache and icon retry after time --- Cargo.toml | 9 ++++----- src/cache.rs | 25 +++++++++++++++++++++---- src/lib.rs | 29 +++++++++++++++++++++++++++-- src/theme/mod.rs | 10 ++++++++-- src/theme/paths.rs | 7 +++---- 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 344c375..37b5731 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,10 @@ readme = "README.md" keywords = ["icons", "gui", "freedesktop"] [dependencies] -dirs = "5.0.1" -thiserror = "1.0.56" -once_cell = "1.19.0" -xdg = "2.5.2" -tracing = "0.1.41" +dirs = "5.0" +thiserror = "2.0" +xdg = "2.5" +tracing = "0.1.0" ini_core = "0.2.0" [dev-dependencies] diff --git a/src/cache.rs b/src/cache.rs index 2dbc0df..f5d7d19 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,9 +1,10 @@ -use once_cell::sync::Lazy; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; use std::sync::Mutex; +use std::time::Instant; -pub(crate) static CACHE: Lazy = Lazy::new(Cache::default); +pub(crate) static CACHE: LazyLock = LazyLock::new(Cache::default); type IconMap = BTreeMap<(String, u16, u16), CacheEntry>; type ThemeMap = BTreeMap; @@ -13,7 +14,7 @@ pub(crate) struct Cache(Mutex); #[derive(Debug, Clone, PartialEq)] pub enum CacheEntry { // We already looked for this and nothing was found, indicates we should not try to perform a lookup. - NotFound, + NotFound(Instant), // We have this entry. Found(PathBuf), // We don't know this entry yet, indicate we should perform a lookup. @@ -21,6 +22,10 @@ pub enum CacheEntry { } impl Cache { + pub fn clear(&self) { + self.0.lock().unwrap().clear(); + } + pub fn insert>( &self, theme: &str, @@ -33,7 +38,7 @@ impl Cache { let entry = icon_path .as_ref() .map(|path| CacheEntry::Found(path.as_ref().to_path_buf())) - .unwrap_or(CacheEntry::NotFound); + .unwrap_or(CacheEntry::NotFound(Instant::now())); match theme_map.get_mut(theme) { Some(icon_map) => { @@ -56,4 +61,16 @@ impl Cache { .and_then(|path| path.cloned()) .unwrap_or(CacheEntry::Unknown) } + + pub fn reset_none(&self) { + let mut theme_map = self.0.lock().unwrap(); + + for (_theme_name, theme) in theme_map.iter_mut() { + for (_icon_data, cached_icon) in theme.iter_mut() { + if matches!(cached_icon, CacheEntry::NotFound(_)) { + *cached_icon = CacheEntry::Unknown; + } + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index 02854cb..c8a4db6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ use crate::cache::{CacheEntry, CACHE}; use crate::theme::{try_build_icon_path, THEMES}; use std::io::BufRead; use std::path::PathBuf; +use std::time::Instant; mod cache; mod theme; @@ -189,6 +190,7 @@ impl<'a> LookupBuilder<'a> { /// .with_size(48) /// .find(); /// # } + #[inline] pub fn with_size(mut self, size: u16) -> Self { self.size = size; self @@ -205,6 +207,7 @@ impl<'a> LookupBuilder<'a> { /// .with_scale(2) /// .find(); /// # } + #[inline] pub fn with_scale(mut self, scale: u16) -> Self { self.scale = scale; self @@ -220,6 +223,7 @@ impl<'a> LookupBuilder<'a> { /// .with_theme("Papirus") /// .find(); /// # } + #[inline] pub fn with_theme<'b: 'a>(mut self, theme: &'b str) -> Self { self.theme = theme; self @@ -240,6 +244,7 @@ impl<'a> LookupBuilder<'a> { /// .with_cache() /// .find(); /// # } + #[inline] pub fn with_cache(mut self) -> Self { self.cache = true; self @@ -258,6 +263,7 @@ impl<'a> LookupBuilder<'a> { /// .force_svg() /// .find(); /// # } + #[inline] pub fn force_svg(mut self) -> Self { self.force_svg = true; self @@ -266,7 +272,12 @@ impl<'a> LookupBuilder<'a> { /// Execute the current lookup /// if no icon is found in the current theme fallback to /// `/usr/share/icons/hicolor` theme and then to `/usr/share/pixmaps`. + #[inline] pub fn find(self) -> Option { + if self.name.is_empty() { + return None; + } + // Lookup for an icon in the given theme and fallback to 'hicolor' default theme self.lookup_in_theme() } @@ -290,8 +301,12 @@ impl<'a> LookupBuilder<'a> { if self.cache { match self.cache_lookup(self.theme) { CacheEntry::Found(icon) => return Some(icon), - CacheEntry::NotFound => return None, - _ => () + CacheEntry::NotFound(last_check) + if last_check.duration_since(Instant::now()).as_secs() < 5 => + { + return None + } + _ => (), } } @@ -364,6 +379,16 @@ impl<'a> LookupBuilder<'a> { }) } + #[inline] + pub fn cache_clear(&mut self) { + CACHE.clear(); + } + + #[inline] + pub fn cache_reset_none(&mut self) { + CACHE.reset_none(); + } + #[inline] fn cache_lookup(&self, theme: &str) -> CacheEntry { CACHE.get(theme, self.size, self.scale, self.name) diff --git a/src/theme/mod.rs b/src/theme/mod.rs index 55fbabd..f082cb8 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -1,9 +1,9 @@ use crate::theme::error::ThemeError; use crate::theme::paths::ThemePath; -use once_cell::sync::Lazy; pub(crate) use paths::BASE_PATHS; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; +use std::sync::LazyLock; mod directories; pub mod error; @@ -12,8 +12,9 @@ mod paths; type Result = std::result::Result; -pub static THEMES: Lazy>> = Lazy::new(get_all_themes); +pub static THEMES: LazyLock>> = LazyLock::new(get_all_themes); +#[inline] pub fn read_ini_theme(path: &Path) -> String { std::fs::read_to_string(path).unwrap_or_default() } @@ -25,6 +26,7 @@ pub struct Theme { } impl Theme { + #[inline] pub fn try_get_icon( &self, name: &str, @@ -32,11 +34,13 @@ impl Theme { scale: u16, force_svg: bool, ) -> Option { + eprintln!("try_get_icon: {name}"); let file = read_ini_theme(&self.index); self.try_get_icon_exact_size(file.as_str(), name, size, scale, force_svg) .or_else(|| self.try_get_icon_closest_size(file.as_str(), name, size, scale, force_svg)) } + #[inline] fn try_get_icon_exact_size( &self, file: &str, @@ -49,6 +53,7 @@ impl Theme { .find_map(|path| try_build_icon_path(name, path, force_svg)) } + #[inline] fn match_size<'a>( &'a self, file: &'a str, @@ -62,6 +67,7 @@ impl Theme { .map(|dir| self.path().join(dir)) } + #[inline] fn try_get_icon_closest_size( &self, file: &str, diff --git a/src/theme/paths.rs b/src/theme/paths.rs index dea8f48..7d88b00 100644 --- a/src/theme/paths.rs +++ b/src/theme/paths.rs @@ -1,13 +1,12 @@ -use std::path::PathBuf; - use dirs::home_dir; -use once_cell::sync::Lazy; +use std::path::PathBuf; +use std::sync::LazyLock; use xdg::BaseDirectories; use crate::theme; use crate::theme::error::ThemeError; -pub(crate) static BASE_PATHS: Lazy> = Lazy::new(icon_theme_base_paths); +pub(crate) static BASE_PATHS: LazyLock> = LazyLock::new(icon_theme_base_paths); /// Look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons, in $XDG_DATA_DIRS/pixmaps and in /usr/share/pixmaps (in that order). /// Paths that are not found are filtered out.