feat: add some benches to compare with linicon

This commit is contained in:
Paul Delafosse 2022-05-12 15:34:02 +02:00
parent 6515a02881
commit e40fbfa916
6 changed files with 124 additions and 62 deletions

View file

@ -14,4 +14,9 @@ once_cell = "1.10.0"
[dev-dependencies] [dev-dependencies]
speculoos = "0.9.0" speculoos = "0.9.0"
anyhow = "1.0.57" anyhow = "1.0.57"
linicon = "2.3.0" linicon = "2.3.0"
criterion = "0.3"
[[bench]]
name = "simple_lookup"
harness = false

17
benches/simple_lookup.rs Normal file
View file

@ -0,0 +1,17 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use freedesktop_icons::lookup;
pub fn simple_lookup(c: &mut Criterion) {
c.bench_function("lookup firefox", |b| {
b.iter(|| lookup("firefox").find_one())
});
}
pub fn simple_lookup_linicon(c: &mut Criterion) {
c.bench_function("lookup firefox linicon", |b| {
b.iter(|| linicon::lookup_icon("firefox").next().unwrap().unwrap())
});
}
criterion_group!(benches, simple_lookup, simple_lookup_linicon);
criterion_main!(benches);

View file

@ -1,54 +1,117 @@
use crate::theme::{try_build_icon_path, FALL_BACK_THEMES, THEMES}; use crate::theme::{try_build_icon_path, THEMES};
use std::path::PathBuf; use std::path::PathBuf;
pub mod theme; pub mod theme;
pub fn lookup(name: &str, size: u16, scale: u16, theme: &str) -> Option<PathBuf> { pub fn lookup(name: &str) -> LookupBuilder {
if let Some(theme) = THEMES.get(theme) { LookupBuilder::new(name)
let icon = theme.try_get_icon(name, size, scale); }
if icon.is_some() {
return icon; pub struct LookupBuilder<'a> {
name: &'a str,
scale: u16,
size: u16,
theme: Option<&'a str>,
}
impl<'a> LookupBuilder<'a> {
pub fn with_size(mut self, scale: u16) -> Self {
self.scale = scale;
self
}
pub fn with_scale(mut self, size: u16) -> Self {
self.size = size;
self
}
pub fn with_theme<'b: 'a>(mut self, theme: &'b str) -> Self {
self.theme = Some(theme);
self
}
fn new<'b: 'a>(name: &'b str) -> Self {
Self {
name,
scale: 1,
size: 24,
theme: None,
} }
} }
for theme in FALL_BACK_THEMES.iter() { pub fn find_one(self) -> Option<PathBuf> {
let icon = theme.try_get_icon(name, size, scale); let name = self.name;
if icon.is_some() { let size = self.size;
return icon; let scale = self.scale;
}
}
try_build_icon_path(name, "/usr/share/pixmaps") // We have a theme name, lookup -> fallback - exit
if let Some(theme) = self.theme.and_then(|theme| THEMES.get(theme)) {
let icon = theme.try_get_icon(name, size, scale);
if icon.is_some() {
return icon;
}
// hicolor fallback
if let Some(fallback) = THEMES.get("hicolor") {
let icon = fallback.try_get_icon(name, size, scale);
if icon.is_some() {
return icon;
}
}
} else {
// No theme let's look everywhere
for theme in THEMES.values() {
let icon = theme.try_get_icon(name, size, scale);
if icon.is_some() {
return icon;
}
}
}
// Last chance
try_build_icon_path(name, "/usr/share/pixmaps")
}
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::lookup; use crate::lookup;
use speculoos::prelude::*; use speculoos::prelude::*;
use std::path::PathBuf;
#[test] #[test]
fn compare_to_linincon() { fn simple_lookup() {
let firefox = lookup("firefox").find_one();
assert_that!(firefox).is_some();
}
#[test]
fn compare_to_linincon_with_theme() {
let lin_wireshark = linicon::lookup_icon("wireshark") let lin_wireshark = linicon::lookup_icon("wireshark")
.next() .next()
.unwrap() .unwrap()
.unwrap() .unwrap()
.path; .path;
let wireshark = lookup("wireshark", 16, 1, "Papirus"); let wireshark = lookup("wireshark")
.with_size(16)
.with_scale(1)
.with_theme("Papirus")
.find_one();
assert_that!(wireshark).is_some().is_equal_to(lin_wireshark) assert_that!(wireshark).is_some().is_equal_to(lin_wireshark)
} }
#[test] #[test]
fn compare_to_linicon_in_pixmap() { fn compare_to_linicon_in_pixmap() {
let archlinux_logo = linicon::lookup_icon("archlinux-logo").next(); let archlinux_logo = lookup("archlinux-logo")
.with_size(16)
assert_that!(archlinux_logo).is_some(); .with_scale(1)
.with_theme("Papirus")
let archlinux_logo = lookup("archlinux-logo", 16, 1, "Papirus"); .find_one();
assert_that!(archlinux_logo) assert_that!(archlinux_logo)
.is_some() .is_some()
.has_file_name("/usr/share/pixmaps/archlinux-logo.png"); .is_equal_to(PathBuf::from("/usr/share/pixmaps/archlinux-logo.png"));
} }
} }

View file

@ -1,5 +1,5 @@
use crate::theme::error::ThemeError; use crate::theme::error::ThemeError;
use crate::theme::paths::{ThemePath, FALLBACK_PATHS}; use crate::theme::paths::ThemePath;
use ini::Ini; use ini::Ini;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use paths::BASE_PATHS; use paths::BASE_PATHS;
@ -17,9 +17,6 @@ type Result<T> = std::result::Result<T, ThemeError>;
pub static THEMES: Lazy<BTreeMap<String, Theme>> = pub static THEMES: Lazy<BTreeMap<String, Theme>> =
Lazy::new(|| get_all_themes().expect("Failed to get theme paths")); Lazy::new(|| get_all_themes().expect("Failed to get theme paths"));
pub static FALL_BACK_THEMES: Lazy<Vec<Theme>> =
Lazy::new(|| fallback_themes().expect("Failed to get theme paths"));
pub struct Theme { pub struct Theme {
path: ThemePath, path: ThemePath,
index: Ini, index: Ini,
@ -28,7 +25,7 @@ pub struct Theme {
impl Theme { impl Theme {
pub fn try_get_icon(&self, name: &str, size: u16, scale: u16) -> Option<PathBuf> { pub fn try_get_icon(&self, name: &str, size: u16, scale: u16) -> Option<PathBuf> {
self.try_get_icon_exact_size(name, size, scale) self.try_get_icon_exact_size(name, size, scale)
.or(self.try_get_icon_closest_size(name, size, scale)) .or_else(|| self.try_get_icon_closest_size(name, size, scale))
} }
fn try_get_icon_exact_size(&self, name: &str, size: u16, scale: u16) -> Option<PathBuf> { fn try_get_icon_exact_size(&self, name: &str, size: u16, scale: u16) -> Option<PathBuf> {
@ -89,7 +86,7 @@ pub(super) fn try_build_icon_path<P: AsRef<Path>>(name: &str, path: P) -> Option
} }
// Iter through the base paths and get all theme directories // Iter through the base paths and get all theme directories
fn get_all_themes() -> Result<BTreeMap<String, Theme>> { pub fn get_all_themes() -> Result<BTreeMap<String, Theme>> {
let mut icon_themes = BTreeMap::new(); let mut icon_themes = BTreeMap::new();
for theme_base_dir in BASE_PATHS.iter() { for theme_base_dir in BASE_PATHS.iter() {
for entry in theme_base_dir.read_dir()? { for entry in theme_base_dir.read_dir()? {
@ -103,20 +100,6 @@ fn get_all_themes() -> Result<BTreeMap<String, Theme>> {
Ok(icon_themes) Ok(icon_themes)
} }
fn fallback_themes() -> Result<Vec<Theme>> {
let mut icon_themes = vec![];
for theme_base_dir in FALLBACK_PATHS.iter() {
for entry in theme_base_dir.read_dir()? {
let entry = entry?;
if let Some(theme) = Theme::from_path(entry.path()) {
icon_themes.push(theme);
}
}
}
Ok(icon_themes)
}
pub fn theme_names() -> Vec<&'static str> { pub fn theme_names() -> Vec<&'static str> {
THEMES THEMES
.values() .values()
@ -124,7 +107,7 @@ pub fn theme_names() -> Vec<&'static str> {
.filter_map(|index| { .filter_map(|index| {
index index
.section(Some("Icon Theme")) .section(Some("Icon Theme"))
.and_then(|section| section.get("Name").map(|s| s)) .and_then(|section| section.get("Name"))
}) })
.collect() .collect()
} }

View file

@ -4,18 +4,14 @@ use ini::Properties;
impl Theme { impl Theme {
pub(super) fn get_all_directories(&self) -> Vec<Directory> { pub(super) fn get_all_directories(&self) -> Vec<Directory> {
let dir_names = self.directories().unwrap_or(vec![]); self.directories()
let mut dirs = vec![]; .unwrap_or_default()
for dir in dir_names { .iter()
let dir = self.get_directory(dir); .filter_map(|name| self.get_directory(name))
if let Some(dir) = dir { .collect()
dirs.push(dir);
}
}
dirs
} }
// TODO: use me
fn scaled_directories(&self) -> Option<Vec<&str>> { fn scaled_directories(&self) -> Option<Vec<&str>> {
self.get_icon_theme_section() self.get_icon_theme_section()
.and_then(|props| props.get("ScaledDirectories")) .and_then(|props| props.get("ScaledDirectories"))

View file

@ -5,15 +5,7 @@ use ini::Ini;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::path::PathBuf; use std::path::PathBuf;
pub(crate) static BASE_PATHS: Lazy<Vec<PathBuf>> = Lazy::new(|| icon_theme_base_paths()); pub(crate) static BASE_PATHS: Lazy<Vec<PathBuf>> = Lazy::new(icon_theme_base_paths);
pub(crate) static FALLBACK_PATHS: Lazy<Vec<PathBuf>> = Lazy::new(|| {
vec![
data_dir()
.expect("Failed to get DATA_DIR")
.join("icons/hicolor"),
PathBuf::from("usr/share/icons/hicolor"),
]
});
/// Look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons and in /usr/share/pixmaps (in that order). /// Look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons and in /usr/share/pixmaps (in that order).
/// Paths that are not found are filtered out. /// Paths that are not found are filtered out.
@ -56,6 +48,12 @@ mod test {
use anyhow::Result; use anyhow::Result;
use speculoos::prelude::*; use speculoos::prelude::*;
#[test]
fn should_get_all_themes() {
let themes = get_all_themes().unwrap();
assert_that!(themes.get("hicolor")).is_some();
}
#[test] #[test]
fn should_get_theme_paths_ordered() { fn should_get_theme_paths_ordered() {
let base_paths = icon_theme_base_paths(); let base_paths = icon_theme_base_paths();