mirror of
https://github.com/danbulant/icon
synced 2026-05-19 04:08:36 +00:00
Remove 🐄 to simplify API, reducing lifetimes
Okay. I'll admit it. It was a bad idea. You don't need zero-copy theme parsing if you're only going to use copied versions everywhere anyways.
This commit is contained in:
parent
bae6cb822e
commit
b58a34b589
3 changed files with 35 additions and 109 deletions
|
|
@ -50,7 +50,6 @@
|
|||
//! - it does not scan "standalone" icons correctly, such as those usually found in `/usr/share/pixmaps`.
|
||||
//! - it adopts a one-shot approach, repeating all parsing and file-finding work for each icon.
|
||||
//! - it does not provide support for caching.
|
||||
//! - it does not support zero-copy parsing of icon theme metadata.
|
||||
//!
|
||||
//! - [icon-loader](https://crates.io/crates/icon-loader) also implements icon finding, but:
|
||||
//! - like `linicon`, it does not scan "standalone" icons correctly.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::icon::IconFile;
|
||||
use crate::theme::{OwnedThemeDescriptor, Theme, ThemeDescriptor, ThemeParseError};
|
||||
use crate::theme::{Theme, ThemeDescriptor, ThemeParseError};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -100,11 +100,11 @@ pub struct IconLocations {
|
|||
}
|
||||
|
||||
impl IconLocations {
|
||||
pub fn resolve(&self) -> Vec<Arc<Theme<'static>>> {
|
||||
pub fn resolve(&self) -> Vec<Arc<Theme>> {
|
||||
self.resolve_only(self.themes_directories.keys())
|
||||
}
|
||||
|
||||
pub fn resolve_only<I, S>(&self, theme_names: I) -> Vec<Arc<Theme<'static>>>
|
||||
pub fn resolve_only<I, S>(&self, theme_names: I) -> Vec<Arc<Theme>>
|
||||
where
|
||||
I: IntoIterator<Item = S>,
|
||||
S: AsRef<OsStr>,
|
||||
|
|
@ -148,7 +148,7 @@ impl IconLocations {
|
|||
|
||||
// Collect all parents of this theme:
|
||||
for parent in parents {
|
||||
collect_themes(parent.as_ref().as_ref(), locations, themes);
|
||||
collect_themes(parent.as_ref(), locations, themes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ impl IconLocations {
|
|||
full_themes
|
||||
}
|
||||
|
||||
pub fn theme_description<S>(&self, internal_name: S) -> std::io::Result<OwnedThemeDescriptor>
|
||||
pub fn theme_description<S>(&self, internal_name: S) -> std::io::Result<ThemeDescriptor>
|
||||
where
|
||||
S: AsRef<OsStr>,
|
||||
{
|
||||
|
|
|
|||
133
src/theme.rs
133
src/theme.rs
|
|
@ -1,32 +1,26 @@
|
|||
use crate::icon::IconFile;
|
||||
use crate::theme::ThemeParseError::MissingRequiredAttribute;
|
||||
use freedesktop_entry_parser::low_level::{EntryIter, SectionBytes};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type OwnedIcons = Icons<'static>;
|
||||
pub type OwnedThemeDescriptor = ThemeDescriptor<'static>;
|
||||
pub type OwnedThemeIndex = ThemeIndex<'static>;
|
||||
pub type OwnedDirectoryIndex = DirectoryIndex<'static>;
|
||||
|
||||
pub struct Icons<'a> {
|
||||
pub struct Icons {
|
||||
pub standalone_icons: Vec<IconFile>,
|
||||
pub themes: HashMap<OsString, Arc<Theme<'a>>>,
|
||||
pub themes: HashMap<OsString, Arc<Theme>>,
|
||||
}
|
||||
|
||||
pub struct Theme<'a> {
|
||||
pub description: ThemeDescriptor<'a>,
|
||||
pub parents: Vec<Arc<Theme<'a>>>,
|
||||
pub struct Theme {
|
||||
pub description: ThemeDescriptor,
|
||||
pub parents: Vec<Arc<Theme>>,
|
||||
}
|
||||
|
||||
pub struct ThemeDescriptor<'a> {
|
||||
pub struct ThemeDescriptor {
|
||||
pub internal_name: String,
|
||||
pub base_dirs: Vec<PathBuf>,
|
||||
pub index_location: PathBuf,
|
||||
pub index: ThemeIndex<'a>,
|
||||
pub index: ThemeIndex,
|
||||
// additional groups?
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +42,7 @@ pub enum ThemeParseError {
|
|||
ParseError(#[from] freedesktop_entry_parser::ParseError),
|
||||
}
|
||||
|
||||
impl ThemeDescriptor<'_> {
|
||||
impl ThemeDescriptor {
|
||||
pub fn new_from_folders(internal_name: String, folders: Vec<PathBuf>) -> std::io::Result<Self> {
|
||||
let index_location = folders
|
||||
.iter()
|
||||
|
|
@ -65,52 +59,36 @@ impl ThemeDescriptor<'_> {
|
|||
index,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> OwnedThemeDescriptor {
|
||||
theme_into_owned(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn theme_into_owned(theme: ThemeDescriptor) -> OwnedThemeDescriptor {
|
||||
let base_dirs = theme.base_dirs;
|
||||
let index = theme.index.into_owned();
|
||||
|
||||
OwnedThemeDescriptor {
|
||||
base_dirs,
|
||||
index,
|
||||
..theme
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThemeIndex<'a> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub comment: Cow<'a, str>,
|
||||
pub inherits: Vec<Cow<'a, str>>,
|
||||
pub directories: Vec<DirectoryIndex<'a>>,
|
||||
pub struct ThemeIndex {
|
||||
pub name: String,
|
||||
pub comment: String,
|
||||
pub inherits: Vec<String>,
|
||||
pub directories: Vec<DirectoryIndex>,
|
||||
pub hidden: bool,
|
||||
pub example: Option<Cow<'a, str>>,
|
||||
pub example: Option<String>,
|
||||
}
|
||||
|
||||
impl<'a> ThemeIndex<'a> {
|
||||
pub fn parse_from_file(path: &Path) -> std::io::Result<OwnedThemeIndex> {
|
||||
impl ThemeIndex {
|
||||
pub fn parse_from_file(path: &Path) -> std::io::Result<Self> {
|
||||
let bytes = std::fs::read(path)?;
|
||||
let index = ThemeIndex::parse(&bytes).map_err(std::io::Error::other)?;
|
||||
|
||||
Ok(index.into_owned())
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
pub fn parse(bytes: &'a [u8]) -> Result<Self, ThemeParseError> {
|
||||
let mut entry: EntryIter<'a> = freedesktop_entry_parser::low_level::parse_entry(bytes);
|
||||
pub fn parse(bytes: &[u8]) -> Result<Self, ThemeParseError> {
|
||||
let mut entry: EntryIter = freedesktop_entry_parser::low_level::parse_entry(bytes);
|
||||
|
||||
let icon_theme_section: SectionBytes<'a> =
|
||||
let icon_theme_section: SectionBytes =
|
||||
entry.next().ok_or(ThemeParseError::NotAnIconTheme)??;
|
||||
let name: &'a str = find_attr_req(&icon_theme_section, "Name")?;
|
||||
let name: &str = find_attr_req(&icon_theme_section, "Name")?;
|
||||
|
||||
// SPEC: `Comment` is required, but most icon theme developers can't actually be arsed to
|
||||
// include it! To make `icon` practical, we choose a default of an empty string instead.
|
||||
// let comment = find_attr_req(&icon_theme_section, "Comment")?;
|
||||
let comment = find_attr(&icon_theme_section, "Comment")?
|
||||
.unwrap_or("");
|
||||
let comment = find_attr(&icon_theme_section, "Comment")?.unwrap_or("");
|
||||
// If no theme is specified, implementations are required to add the "hicolor" theme to the inheritance tree.
|
||||
let inherits = find_attr(&icon_theme_section, "Inherits")?
|
||||
.iter()
|
||||
|
|
@ -165,53 +143,23 @@ impl<'a> ThemeIndex<'a> {
|
|||
example: example.map(Into::into),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> OwnedThemeIndex {
|
||||
theme_index_into_owned(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn theme_index_into_owned(index: ThemeIndex) -> OwnedThemeIndex {
|
||||
let name = index.name.into_owned().into();
|
||||
let comment = index.comment.into_owned().into();
|
||||
let inherits = index
|
||||
.inherits
|
||||
.into_iter()
|
||||
.map(Cow::into_owned)
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
let directories = index
|
||||
.directories
|
||||
.into_iter()
|
||||
.map(|x| x.into_owned())
|
||||
.collect();
|
||||
let example = index.example.map(Cow::into_owned).map(Into::into);
|
||||
|
||||
OwnedThemeIndex {
|
||||
name,
|
||||
comment,
|
||||
inherits,
|
||||
directories,
|
||||
example,
|
||||
..index
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirectoryIndex<'a> {
|
||||
pub directory_name: Cow<'a, str>,
|
||||
pub struct DirectoryIndex {
|
||||
pub directory_name: String,
|
||||
pub is_scaled_dir: bool,
|
||||
pub size: u32,
|
||||
pub scale: u32,
|
||||
pub context: Option<Cow<'a, str>>,
|
||||
pub context: Option<String>,
|
||||
pub directory_type: DirectoryType,
|
||||
pub max_size: u32,
|
||||
pub min_size: u32,
|
||||
pub threshold: u32,
|
||||
// pub additional_values: HashMap<Cow<'a, str>, Cow<'a, str>>,
|
||||
// pub additional_values: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl<'a> DirectoryIndex<'a> {
|
||||
fn parse(section: SectionBytes<'a>) -> Result<Self, ThemeParseError> {
|
||||
impl DirectoryIndex {
|
||||
fn parse(section: SectionBytes) -> Result<Self, ThemeParseError> {
|
||||
let dir_name = str::from_utf8(section.title)?;
|
||||
let size: u32 = find_attr_req(§ion, "Size")?.parse()?;
|
||||
let scale: u32 = find_attr(§ion, "Scale")?
|
||||
|
|
@ -299,27 +247,6 @@ impl<'a> DirectoryIndex<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> OwnedDirectoryIndex {
|
||||
dir_index_into_owned(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn dir_index_into_owned(index: DirectoryIndex) -> OwnedDirectoryIndex {
|
||||
let directory_name: Cow<'static, str> = index.directory_name.into_owned().into();
|
||||
let context: Option<Cow<'static, str>> = index.context.map(|c| c.into_owned().into());
|
||||
// let additional_values: HashMap<Cow<'static, str>, Cow<'static, str>> = index
|
||||
// .additional_values
|
||||
// .into_iter()
|
||||
// .map(|(k, v)| (Cow::Owned(k.into_owned()), Cow::Owned(v.into_owned())))
|
||||
// .collect();
|
||||
|
||||
OwnedDirectoryIndex {
|
||||
directory_name,
|
||||
context,
|
||||
// additional_values,
|
||||
..index
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
|
|
@ -345,7 +272,7 @@ impl TryFrom<&str> for DirectoryType {
|
|||
}
|
||||
|
||||
fn find_attr<'a>(
|
||||
section: &SectionBytes<'a>,
|
||||
section: &'a SectionBytes,
|
||||
name: &str,
|
||||
) -> Result<Option<&'a str>, std::str::Utf8Error> {
|
||||
section
|
||||
|
|
@ -357,7 +284,7 @@ fn find_attr<'a>(
|
|||
}
|
||||
|
||||
fn find_attr_req<'a>(
|
||||
section: &SectionBytes<'a>,
|
||||
section: &'a SectionBytes,
|
||||
name: &'static str,
|
||||
) -> Result<&'a str, ThemeParseError> {
|
||||
find_attr(section, name)?.ok_or(MissingRequiredAttribute(name))
|
||||
|
|
|
|||
Loading…
Reference in a new issue