improv: significant memory and cpu usage reduction

This commit is contained in:
Michael Aaron Murphy 2025-01-23 11:18:33 +01:00 committed by Paul Delafosse
parent 4578b5fa25
commit 3dd7647411
7 changed files with 200 additions and 127 deletions

View file

@ -1,34 +1,114 @@
use crate::theme::directories::{Directory, DirectoryType};
use crate::theme::Theme;
use ini::Properties;
fn icon_theme_section(file: &str) -> impl Iterator<Item = (&str, &str)> + '_ {
ini_core::Parser::new(file)
.skip_while(|item| *item != ini_core::Item::Section("Icon Theme"))
.take_while(|item| match item {
ini_core::Item::Section(value) => *value == "Icon Theme",
_ => true,
})
.filter_map(|item| {
if let ini_core::Item::Property(key, value) = item {
Some((key, value?))
} else {
None
}
})
}
#[derive(Debug)]
enum DirectorySection<'a> {
Property(&'a str, &'a str),
EndSection,
Section(&'a str),
}
fn sections(file: &str) -> impl Iterator<Item = DirectorySection> {
ini_core::Parser::new(file).filter_map(move |item| match item {
ini_core::Item::Property(key, Some(value)) => Some(DirectorySection::Property(key, value)),
ini_core::Item::Section(section) => Some(DirectorySection::Section(section)),
ini_core::Item::SectionEnd => Some(DirectorySection::EndSection),
_ => None,
})
}
impl Theme {
pub(super) fn get_all_directories(&self) -> impl Iterator<Item = Directory> {
self.directories()
.into_iter()
.filter_map(|name| self.get_directory(name))
.chain(
self.scaled_directories()
.into_iter()
.filter_map(|name| self.get_directory(name)),
)
pub(super) fn get_all_directories<'a>(
&'a self,
file: &'a str,
) -> impl Iterator<Item = Directory<'a>> + 'a {
let mut iterator = sections(file);
std::iter::from_fn(move || {
let mut name = "";
let mut size = None;
let mut max_size = None;
let mut min_size = None;
let mut threshold = None;
let mut scale = None;
// let mut context = None;
let mut dtype = DirectoryType::default();
#[allow(clippy::while_let_on_iterator)]
while let Some(event) = iterator.next() {
match event {
DirectorySection::Property(key, value) => {
if name.is_empty() || name == "Icon Theme" {
continue;
}
match key {
"Size" => size = str::parse(value).ok(),
"Scale" => scale = str::parse(value).ok(),
// "Context" => context = Some(value),
"Type" => dtype = DirectoryType::from(value),
"MaxSize" => max_size = str::parse(value).ok(),
"MinSize" => min_size = str::parse(value).ok(),
"Threshold" => threshold = str::parse(value).ok(),
_ => (),
}
}
DirectorySection::Section(new_name) => {
name = new_name;
size = None;
max_size = None;
min_size = None;
threshold = None;
scale = None;
dtype = DirectoryType::default();
}
DirectorySection::EndSection => {
if name.is_empty() || name == "Icon Theme" {
continue;
}
let size = size.take()?;
return Some(Directory {
name,
size,
scale: scale.unwrap_or(1),
// context,
type_: dtype,
maxsize: max_size.unwrap_or(size),
minsize: min_size.unwrap_or(size),
threshold: threshold.unwrap_or(2),
});
}
}
}
None
})
}
fn scaled_directories(&self) -> Vec<&str> {
self.get_icon_theme_section()
.and_then(|props| props.get("ScaledDirectories"))
.map(|dirs| dirs.split(',').collect())
.unwrap_or_default()
}
fn get_icon_theme_section(&self) -> Option<&Properties> {
self.index.section(Some("Icon Theme"))
}
pub fn inherits(&self) -> Vec<&str> {
self.get_icon_theme_section()
.and_then(|props| props.get("Inherits"))
.map(|parents| {
pub fn inherits<'a>(&self, file: &'a str) -> Vec<&'a str> {
icon_theme_section(file)
.find(|&(key, _)| key == "Inherits")
.map(|(_, parents)| {
parents
.split(',')
// Filtering out 'hicolor' since we are going to fallback there anyway
@ -37,47 +117,6 @@ impl Theme {
})
.unwrap_or_default()
}
fn directories(&self) -> Vec<&str> {
self.index
.section(Some("Icon Theme"))
.and_then(|props| props.get("Directories"))
.map(|dirs| dirs.split(',').collect())
.unwrap_or_default()
}
fn get_directory<'a>(&'a self, name: &'a str) -> Option<Directory<'a>> {
self.index.section(Some(name)).map(|props| {
let size = props
.get("Size")
.and_then(|size| str::parse(size).ok())
.expect("Size not found for icon");
Directory {
name,
size,
scale: props
.get("Scale")
.and_then(|scale| str::parse(scale).ok())
.unwrap_or(1),
type_: props
.get("Type")
.map(DirectoryType::from)
.unwrap_or_default(),
maxsize: props
.get("MaxSize")
.and_then(|max| str::parse(max).ok())
.unwrap_or(size),
minsize: props
.get("MinSize")
.and_then(|min| str::parse(min).ok())
.unwrap_or(size),
threshold: props
.get("Threshold")
.and_then(|thrsh| str::parse(thrsh).ok())
.unwrap_or(2),
}
})
}
}
#[cfg(test)]
@ -88,7 +127,8 @@ mod test {
#[test]
fn should_get_theme_parents() {
for theme in THEMES.get("Arc").unwrap() {
let parents = theme.inherits();
let file = crate::theme::read_ini_theme(&theme.index);
let parents = theme.inherits(&file);
assert_that!(parents).does_not_contain("hicolor");