perf: use rustc-hash for HashMap and HashSet
Since we already depend on `rustc-hash` transiently, this doesn't add any more dependencies. As long as DOS attacks aren't a concern (which I don't think they are?), this should be free performance. In my (admittedly naive) testing, this really improved CPU usage in some cases, which is pretty nice to get for free.
This commit is contained in:
parent
4be92ae8ca
commit
43a9fca4ec
11 changed files with 68 additions and 68 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1496,6 +1496,7 @@ dependencies = [
|
||||||
"recently-used-xbel",
|
"recently-used-xbel",
|
||||||
"regex",
|
"regex",
|
||||||
"rust-embed",
|
"rust-embed",
|
||||||
|
"rustc-hash 2.1.1",
|
||||||
"serde",
|
"serde",
|
||||||
"shlex",
|
"shlex",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ notify-rust = { version = "4", optional = true }
|
||||||
open = "5.3.2"
|
open = "5.3.2"
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
rustc-hash = "2.1"
|
||||||
serde = { version = "1", features = ["serde_derive"] }
|
serde = { version = "1", features = ["serde_derive"] }
|
||||||
shlex = { version = "1.3" }
|
shlex = { version = "1.3" }
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
|
||||||
48
src/app.rs
48
src/app.rs
|
|
@ -47,10 +47,11 @@ use notify_debouncer_full::{
|
||||||
DebouncedEvent, Debouncer, RecommendedCache, new_debouncer,
|
DebouncedEvent, Debouncer, RecommendedCache, new_debouncer,
|
||||||
notify::{self, RecommendedWatcher},
|
notify::{self, RecommendedWatcher},
|
||||||
};
|
};
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use slotmap::Key as SlotMapKey;
|
use slotmap::Key as SlotMapKey;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque},
|
collections::{BTreeMap, BTreeSet, HashMap, VecDeque},
|
||||||
env, fmt, fs,
|
env, fmt, fs,
|
||||||
future::Future,
|
future::Future,
|
||||||
io,
|
io,
|
||||||
|
|
@ -67,6 +68,7 @@ use trash::TrashItem;
|
||||||
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
use wayland_client::{Proxy, protocol::wl_output::WlOutput};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
FxOrderMap,
|
||||||
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
||||||
config::{
|
config::{
|
||||||
AppTheme, Config, DesktopConfig, Favorite, IconSizes, TIME_CONFIG_ID, TabConfig,
|
AppTheme, Config, DesktopConfig, Favorite, IconSizes, TIME_CONFIG_ID, TabConfig,
|
||||||
|
|
@ -654,16 +656,16 @@ pub struct App {
|
||||||
dialog_pages: DialogPages,
|
dialog_pages: DialogPages,
|
||||||
dialog_text_input: widget::Id,
|
dialog_text_input: widget::Id,
|
||||||
key_binds: HashMap<KeyBind, Action>,
|
key_binds: HashMap<KeyBind, Action>,
|
||||||
margin: HashMap<window::Id, (f32, f32, f32, f32)>,
|
margin: FxHashMap<window::Id, (f32, f32, f32, f32)>,
|
||||||
mime_app_cache: MimeAppCache,
|
mime_app_cache: MimeAppCache,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
mounter_items: HashMap<MounterKey, MounterItems>,
|
mounter_items: FxHashMap<MounterKey, MounterItems>,
|
||||||
must_save_sort_names: bool,
|
must_save_sort_names: bool,
|
||||||
network_drive_connecting: Option<(MounterKey, String)>,
|
network_drive_connecting: Option<(MounterKey, String)>,
|
||||||
network_drive_input: String,
|
network_drive_input: String,
|
||||||
#[cfg(feature = "notify")]
|
#[cfg(feature = "notify")]
|
||||||
notification_opt: Option<Arc<Mutex<notify_rust::NotificationHandle>>>,
|
notification_opt: Option<Arc<Mutex<notify_rust::NotificationHandle>>>,
|
||||||
overlap: HashMap<String, (window::Id, Rectangle)>,
|
overlap: FxHashMap<String, (window::Id, Rectangle)>,
|
||||||
pending_operation_id: u64,
|
pending_operation_id: u64,
|
||||||
pending_operations: BTreeMap<u64, (Operation, Controller)>,
|
pending_operations: BTreeMap<u64, (Operation, Controller)>,
|
||||||
progress_operations: BTreeSet<u64>,
|
progress_operations: BTreeSet<u64>,
|
||||||
|
|
@ -673,17 +675,17 @@ pub struct App {
|
||||||
search_id: widget::Id,
|
search_id: widget::Id,
|
||||||
size: Option<Size>,
|
size: Option<Size>,
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
layer_sizes: HashMap<window::Id, Size>,
|
layer_sizes: FxHashMap<window::Id, Size>,
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
surface_ids: HashMap<WlOutput, WindowId>,
|
surface_ids: FxHashMap<WlOutput, WindowId>,
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
surface_names: HashMap<WindowId, String>,
|
surface_names: FxHashMap<WindowId, String>,
|
||||||
toasts: widget::toaster::Toasts<Message>,
|
toasts: widget::toaster::Toasts<Message>,
|
||||||
watcher_opt: Option<(
|
watcher_opt: Option<(
|
||||||
Debouncer<RecommendedWatcher, RecommendedCache>,
|
Debouncer<RecommendedWatcher, RecommendedCache>,
|
||||||
HashSet<PathBuf>,
|
FxHashSet<PathBuf>,
|
||||||
)>,
|
)>,
|
||||||
windows: HashMap<window::Id, WindowKind>,
|
windows: FxHashMap<window::Id, WindowKind>,
|
||||||
nav_dnd_hover: Option<(Location, Instant)>,
|
nav_dnd_hover: Option<(Location, Instant)>,
|
||||||
tab_dnd_hover: Option<(Entity, Instant)>,
|
tab_dnd_hover: Option<(Entity, Instant)>,
|
||||||
nav_drag_id: DragId,
|
nav_drag_id: DragId,
|
||||||
|
|
@ -699,7 +701,7 @@ impl App {
|
||||||
// Associate all paths to its MIME type
|
// Associate all paths to its MIME type
|
||||||
// This allows handling paths as groups if possible, such as launching a single video
|
// This allows handling paths as groups if possible, such as launching a single video
|
||||||
// player that is passed every path.
|
// player that is passed every path.
|
||||||
let mut groups: HashMap<Mime, Vec<PathBuf>> = HashMap::new();
|
let mut groups: FxHashMap<Mime, Vec<PathBuf>> = FxHashMap::default();
|
||||||
let mut all_archives = true;
|
let mut all_archives = true;
|
||||||
let supported_archive_types = crate::archive::SUPPORTED_ARCHIVE_TYPES
|
let supported_archive_types = crate::archive::SUPPORTED_ARCHIVE_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -915,7 +917,7 @@ impl App {
|
||||||
|
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
fn handle_overlap(&mut self) {
|
fn handle_overlap(&mut self) {
|
||||||
let mut overlaps: HashMap<_, _> = self
|
let mut overlaps: FxHashMap<_, _> = self
|
||||||
.windows
|
.windows
|
||||||
.keys()
|
.keys()
|
||||||
.map(|k| (*k, (0., 0., 0., 0.)))
|
.map(|k| (*k, (0., 0., 0., 0.)))
|
||||||
|
|
@ -1573,7 +1575,7 @@ impl App {
|
||||||
|
|
||||||
fn update_watcher(&mut self) -> Task<Message> {
|
fn update_watcher(&mut self) -> Task<Message> {
|
||||||
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
||||||
let mut new_paths = HashSet::new();
|
let mut new_paths = FxHashSet::default();
|
||||||
for entity in self.tab_model.iter() {
|
for entity in self.tab_model.iter() {
|
||||||
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
if let Some(tab) = self.tab_model.data::<Tab>(entity) {
|
||||||
if let Some(path) = tab.location.path_opt() {
|
if let Some(path) = tab.location.path_opt() {
|
||||||
|
|
@ -1942,7 +1944,7 @@ impl App {
|
||||||
fn get_apps_for_mime(&self, mime_type: &Mime) -> Vec<(&MimeApp, MimeAppMatch)> {
|
fn get_apps_for_mime(&self, mime_type: &Mime) -> Vec<(&MimeApp, MimeAppMatch)> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
|
|
||||||
let mut dedupe = HashSet::new();
|
let mut dedupe = FxHashSet::default();
|
||||||
|
|
||||||
// start with exact matches
|
// start with exact matches
|
||||||
for mime_app in self.mime_app_cache.get(mime_type) {
|
for mime_app in self.mime_app_cache.get(mime_type) {
|
||||||
|
|
@ -2124,16 +2126,16 @@ impl Application for App {
|
||||||
dialog_pages: DialogPages::new(),
|
dialog_pages: DialogPages::new(),
|
||||||
dialog_text_input: widget::Id::unique(),
|
dialog_text_input: widget::Id::unique(),
|
||||||
key_binds,
|
key_binds,
|
||||||
margin: HashMap::new(),
|
margin: FxHashMap::default(),
|
||||||
mime_app_cache: MimeAppCache::new(),
|
mime_app_cache: MimeAppCache::new(),
|
||||||
modifiers: Modifiers::empty(),
|
modifiers: Modifiers::empty(),
|
||||||
mounter_items: HashMap::new(),
|
mounter_items: FxHashMap::default(),
|
||||||
must_save_sort_names: false,
|
must_save_sort_names: false,
|
||||||
network_drive_connecting: None,
|
network_drive_connecting: None,
|
||||||
network_drive_input: String::new(),
|
network_drive_input: String::new(),
|
||||||
#[cfg(feature = "notify")]
|
#[cfg(feature = "notify")]
|
||||||
notification_opt: None,
|
notification_opt: None,
|
||||||
overlap: HashMap::new(),
|
overlap: FxHashMap::default(),
|
||||||
pending_operation_id: 0,
|
pending_operation_id: 0,
|
||||||
pending_operations: BTreeMap::new(),
|
pending_operations: BTreeMap::new(),
|
||||||
progress_operations: BTreeSet::new(),
|
progress_operations: BTreeSet::new(),
|
||||||
|
|
@ -2143,12 +2145,12 @@ impl Application for App {
|
||||||
search_id: widget::Id::unique(),
|
search_id: widget::Id::unique(),
|
||||||
size: None,
|
size: None,
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
surface_ids: HashMap::new(),
|
surface_ids: FxHashMap::default(),
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
surface_names: HashMap::new(),
|
surface_names: FxHashMap::default(),
|
||||||
toasts: widget::toaster::Toasts::new(Message::CloseToast),
|
toasts: widget::toaster::Toasts::new(Message::CloseToast),
|
||||||
watcher_opt: None,
|
watcher_opt: None,
|
||||||
windows: HashMap::new(),
|
windows: FxHashMap::default(),
|
||||||
nav_dnd_hover: None,
|
nav_dnd_hover: None,
|
||||||
tab_dnd_hover: None,
|
tab_dnd_hover: None,
|
||||||
nav_drag_id: DragId::new(),
|
nav_drag_id: DragId::new(),
|
||||||
|
|
@ -2156,7 +2158,7 @@ impl Application for App {
|
||||||
auto_scroll_speed: None,
|
auto_scroll_speed: None,
|
||||||
file_dialog_opt: None,
|
file_dialog_opt: None,
|
||||||
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
#[cfg(all(feature = "wayland", feature = "desktop-applet"))]
|
||||||
layer_sizes: HashMap::new(),
|
layer_sizes: FxHashMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut commands = vec![app.update_config()];
|
let mut commands = vec![app.update_config()];
|
||||||
|
|
@ -3211,7 +3213,7 @@ impl Application for App {
|
||||||
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
||||||
{
|
{
|
||||||
Some(watcher) => {
|
Some(watcher) => {
|
||||||
self.watcher_opt = Some((watcher, HashSet::new()));
|
self.watcher_opt = Some((watcher, FxHashSet::default()));
|
||||||
return self.update_watcher();
|
return self.update_watcher();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -4678,8 +4680,8 @@ impl Application for App {
|
||||||
Message::SaveSortNames => {
|
Message::SaveSortNames => {
|
||||||
self.must_save_sort_names = false;
|
self.must_save_sort_names = false;
|
||||||
if let Some(state_handler) = self.state_handler.as_ref() {
|
if let Some(state_handler) = self.state_handler.as_ref() {
|
||||||
if let Err(err) =
|
if let Err(err) = state_handler
|
||||||
state_handler.set::<ordermap::OrderMap<String, (HeadingOptions, bool)>>(
|
.set::<FxOrderMap<String, (HeadingOptions, bool)>>(
|
||||||
"sort_names",
|
"sort_names",
|
||||||
self.state.sort_names.clone(),
|
self.state.sort_names.clone(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ use cosmic::{
|
||||||
iced::Subscription,
|
iced::Subscription,
|
||||||
theme,
|
theme,
|
||||||
};
|
};
|
||||||
use ordermap::OrderMap;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
FxOrderMap,
|
||||||
app::App,
|
app::App,
|
||||||
tab::{HeadingOptions, Location, View},
|
tab::{HeadingOptions, Location, View},
|
||||||
};
|
};
|
||||||
|
|
@ -115,13 +115,13 @@ pub enum TypeToSearch {
|
||||||
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub sort_names: ordermap::OrderMap<String, (HeadingOptions, bool)>,
|
pub sort_names: FxOrderMap<String, (HeadingOptions, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sort_names: OrderMap::from_iter(dirs::download_dir().into_iter().map(|dir| {
|
sort_names: FxOrderMap::from_iter(dirs::download_dir().into_iter().map(|dir| {
|
||||||
(
|
(
|
||||||
Location::Path(dir).normalize().to_string(),
|
Location::Path(dir).normalize().to_string(),
|
||||||
(HeadingOptions::Modified, false),
|
(HeadingOptions::Modified, false),
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,10 @@ use notify_debouncer_full::{
|
||||||
notify::{self, RecommendedWatcher},
|
notify::{self, RecommendedWatcher},
|
||||||
};
|
};
|
||||||
use recently_used_xbel::update_recently_used;
|
use recently_used_xbel::update_recently_used;
|
||||||
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
env, fmt, fs,
|
env, fmt, fs,
|
||||||
num::NonZeroU16,
|
num::NonZeroU16,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
|
@ -509,7 +510,7 @@ struct App {
|
||||||
filter_selected: Option<usize>,
|
filter_selected: Option<usize>,
|
||||||
filename_id: widget::Id,
|
filename_id: widget::Id,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
mounter_items: HashMap<MounterKey, MounterItems>,
|
mounter_items: FxHashMap<MounterKey, MounterItems>,
|
||||||
nav_model: segmented_button::SingleSelectModel,
|
nav_model: segmented_button::SingleSelectModel,
|
||||||
result_opt: Option<DialogResult>,
|
result_opt: Option<DialogResult>,
|
||||||
search_id: widget::Id,
|
search_id: widget::Id,
|
||||||
|
|
@ -517,7 +518,7 @@ struct App {
|
||||||
key_binds: HashMap<KeyBind, Action>,
|
key_binds: HashMap<KeyBind, Action>,
|
||||||
watcher_opt: Option<(
|
watcher_opt: Option<(
|
||||||
Debouncer<RecommendedWatcher, RecommendedCache>,
|
Debouncer<RecommendedWatcher, RecommendedCache>,
|
||||||
HashSet<PathBuf>,
|
FxHashSet<PathBuf>,
|
||||||
)>,
|
)>,
|
||||||
auto_scroll_speed: Option<i16>,
|
auto_scroll_speed: Option<i16>,
|
||||||
}
|
}
|
||||||
|
|
@ -871,7 +872,7 @@ impl App {
|
||||||
|
|
||||||
fn update_watcher(&mut self) -> Task<Message> {
|
fn update_watcher(&mut self) -> Task<Message> {
|
||||||
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
if let Some((mut watcher, old_paths)) = self.watcher_opt.take() {
|
||||||
let mut new_paths = HashSet::new();
|
let mut new_paths = FxHashSet::default();
|
||||||
if let Some(path) = &self.tab.location.path_opt() {
|
if let Some(path) = &self.tab.location.path_opt() {
|
||||||
new_paths.insert(path.to_path_buf());
|
new_paths.insert(path.to_path_buf());
|
||||||
}
|
}
|
||||||
|
|
@ -981,7 +982,7 @@ impl Application for App {
|
||||||
filter_selected: None,
|
filter_selected: None,
|
||||||
filename_id: widget::Id::unique(),
|
filename_id: widget::Id::unique(),
|
||||||
modifiers: Modifiers::empty(),
|
modifiers: Modifiers::empty(),
|
||||||
mounter_items: HashMap::new(),
|
mounter_items: FxHashMap::default(),
|
||||||
nav_model: segmented_button::ModelBuilder::default().build(),
|
nav_model: segmented_button::ModelBuilder::default().build(),
|
||||||
result_opt: None,
|
result_opt: None,
|
||||||
search_id: widget::Id::unique(),
|
search_id: widget::Id::unique(),
|
||||||
|
|
@ -1519,7 +1520,7 @@ impl Application for App {
|
||||||
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
Message::NotifyWatcher(mut watcher_wrapper) => match watcher_wrapper.watcher_opt.take()
|
||||||
{
|
{
|
||||||
Some(watcher) => {
|
Some(watcher) => {
|
||||||
self.watcher_opt = Some((watcher, HashSet::new()));
|
self.watcher_opt = Some((watcher, FxHashSet::default()));
|
||||||
return self.update_watcher();
|
return self.update_watcher();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ pub mod tab;
|
||||||
mod thumbnail_cacher;
|
mod thumbnail_cacher;
|
||||||
mod thumbnailer;
|
mod thumbnailer;
|
||||||
|
|
||||||
|
pub(crate) type FxOrderMap<K, V> = ordermap::OrderMap<K, V, rustc_hash::FxBuildHasher>;
|
||||||
|
|
||||||
pub(crate) fn err_str<T: ToString>(err: T) -> String {
|
pub(crate) fn err_str<T: ToString>(err: T) -> String {
|
||||||
err.to_string()
|
err.to_string()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
use cosmic::desktop;
|
use cosmic::desktop;
|
||||||
use cosmic::widget;
|
use cosmic::widget;
|
||||||
pub use mime_guess::Mime;
|
pub use mime_guess::Mime;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
|
||||||
env,
|
env,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fs, io,
|
fs, io,
|
||||||
|
|
@ -221,8 +221,8 @@ fn filename_eq(path_opt: &Option<PathBuf>, filename: &str) -> bool {
|
||||||
|
|
||||||
pub struct MimeAppCache {
|
pub struct MimeAppCache {
|
||||||
apps: Vec<MimeApp>,
|
apps: Vec<MimeApp>,
|
||||||
cache: HashMap<Mime, Vec<MimeApp>>,
|
cache: FxHashMap<Mime, Vec<MimeApp>>,
|
||||||
icons: HashMap<Mime, Vec<widget::icon::Handle>>,
|
icons: FxHashMap<Mime, Vec<widget::icon::Handle>>,
|
||||||
terminals: Vec<MimeApp>,
|
terminals: Vec<MimeApp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,8 +230,8 @@ impl MimeAppCache {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut mime_app_cache = Self {
|
let mut mime_app_cache = Self {
|
||||||
apps: Vec::new(),
|
apps: Vec::new(),
|
||||||
cache: HashMap::new(),
|
cache: FxHashMap::default(),
|
||||||
icons: HashMap::new(),
|
icons: FxHashMap::default(),
|
||||||
terminals: Vec::new(),
|
terminals: Vec::new(),
|
||||||
};
|
};
|
||||||
mime_app_cache.reload();
|
mime_app_cache.reload();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use cosmic::widget::icon;
|
use cosmic::widget::icon;
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
fs,
|
fs,
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{LazyLock, Mutex},
|
sync::{LazyLock, Mutex},
|
||||||
|
|
@ -18,14 +18,14 @@ struct MimeIconKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MimeIconCache {
|
struct MimeIconCache {
|
||||||
cache: HashMap<MimeIconKey, Option<icon::Handle>>,
|
cache: FxHashMap<MimeIconKey, Option<icon::Handle>>,
|
||||||
shared_mime_info: xdg_mime::SharedMimeInfo,
|
shared_mime_info: xdg_mime::SharedMimeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MimeIconCache {
|
impl MimeIconCache {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cache: HashMap::new(),
|
cache: FxHashMap::default(),
|
||||||
shared_mime_info: xdg_mime::SharedMimeInfo::new(),
|
shared_mime_info: xdg_mime::SharedMimeInfo::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
src/tab.rs
39
src/tab.rs
|
|
@ -49,7 +49,7 @@ use icu::{
|
||||||
use image::ImageDecoder;
|
use image::ImageDecoder;
|
||||||
use jxl_oxide::integration::JxlDecoder;
|
use jxl_oxide::integration::JxlDecoder;
|
||||||
use mime_guess::{Mime, mime};
|
use mime_guess::{Mime, mime};
|
||||||
use ordermap::OrderMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
|
@ -73,6 +73,7 @@ use trash::TrashItemSize;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
FxOrderMap,
|
||||||
app::{Action, PreviewItem, PreviewKind},
|
app::{Action, PreviewItem, PreviewKind},
|
||||||
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
clipboard::{ClipboardCopy, ClipboardKind, ClipboardPaste},
|
||||||
config::{DesktopConfig, ICON_SCALE_MAX, ICON_SIZE_GRID, IconSizes, TabConfig, ThumbCfg},
|
config::{DesktopConfig, ICON_SCALE_MAX, ICON_SIZE_GRID, IconSizes, TabConfig, ThumbCfg},
|
||||||
|
|
@ -100,9 +101,9 @@ const THUMBNAIL_SIZE: u32 = (ICON_SIZE_GRID as u32) * (ICON_SCALE_MAX as u32);
|
||||||
pub static THUMB_SEMAPHORE: LazyLock<tokio::sync::Semaphore> =
|
pub static THUMB_SEMAPHORE: LazyLock<tokio::sync::Semaphore> =
|
||||||
LazyLock::new(|| tokio::sync::Semaphore::const_new(num_cpus::get()));
|
LazyLock::new(|| tokio::sync::Semaphore::const_new(num_cpus::get()));
|
||||||
|
|
||||||
pub(crate) static SORT_OPTION_FALLBACK: LazyLock<HashMap<String, (HeadingOptions, bool)>> =
|
pub(crate) static SORT_OPTION_FALLBACK: LazyLock<FxHashMap<String, (HeadingOptions, bool)>> =
|
||||||
LazyLock::new(|| {
|
LazyLock::new(|| {
|
||||||
HashMap::from_iter(dirs::download_dir().into_iter().map(|dir| {
|
FxHashMap::from_iter(dirs::download_dir().into_iter().map(|dir| {
|
||||||
(
|
(
|
||||||
Location::Path(dir).normalize().to_string(),
|
Location::Path(dir).normalize().to_string(),
|
||||||
(HeadingOptions::Modified, false),
|
(HeadingOptions::Modified, false),
|
||||||
|
|
@ -131,8 +132,8 @@ static MODE_NAMES: LazyLock<Vec<String>> = LazyLock::new(|| {
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
static SPECIAL_DIRS: LazyLock<HashMap<PathBuf, &'static str>> = LazyLock::new(|| {
|
static SPECIAL_DIRS: LazyLock<FxHashMap<PathBuf, &'static str>> = LazyLock::new(|| {
|
||||||
let mut special_dirs = HashMap::new();
|
let mut special_dirs = FxHashMap::default();
|
||||||
if let Some(dir) = dirs::document_dir() {
|
if let Some(dir) = dirs::document_dir() {
|
||||||
special_dirs.insert(dir, "folder-documents");
|
special_dirs.insert(dir, "folder-documents");
|
||||||
}
|
}
|
||||||
|
|
@ -534,25 +535,17 @@ pub enum FsKind {
|
||||||
pub fn fs_kind(metadata: &Metadata) -> FsKind {
|
pub fn fs_kind(metadata: &Metadata) -> FsKind {
|
||||||
//TODO: method to reload remote filesystems dynamically
|
//TODO: method to reload remote filesystems dynamically
|
||||||
//TODO: fix for https://github.com/eminence/procfs/issues/262
|
//TODO: fix for https://github.com/eminence/procfs/issues/262
|
||||||
static DEVICES: LazyLock<HashMap<u64, FsKind>> = LazyLock::new(|| {
|
static DEVICES: LazyLock<FxHashMap<u64, FsKind>> = LazyLock::new(|| {
|
||||||
let mut devices = HashMap::new();
|
let mut devices = FxHashMap::default();
|
||||||
match procfs::process::Process::myself() {
|
match procfs::process::Process::myself() {
|
||||||
Ok(process) => match process.mountinfo() {
|
Ok(process) => match process.mountinfo() {
|
||||||
Ok(mount_infos) => {
|
Ok(mount_infos) => {
|
||||||
for mount_info in mount_infos.iter() {
|
devices = FxHashMap::from_iter(mount_infos.iter().filter_map(|mount_info| {
|
||||||
let mut parts = mount_info.majmin.split(':');
|
let mut parts = mount_info.majmin.split(':');
|
||||||
let Some(major_str) = parts.next() else {
|
let major_str = parts.next()?;
|
||||||
continue;
|
let minor_str = parts.next()?;
|
||||||
};
|
let major = major_str.parse::<libc::c_uint>().ok()?;
|
||||||
let Some(minor_str) = parts.next() else {
|
let minor = minor_str.parse::<libc::c_uint>().ok()?;
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let Ok(major) = major_str.parse::<libc::c_uint>() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let Ok(minor) = minor_str.parse::<libc::c_uint>() else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let dev = libc::makedev(major, minor);
|
let dev = libc::makedev(major, minor);
|
||||||
//TODO: make sure this list is exhaustive
|
//TODO: make sure this list is exhaustive
|
||||||
let kind = match mount_info.fs_type.as_str() {
|
let kind = match mount_info.fs_type.as_str() {
|
||||||
|
|
@ -561,8 +554,8 @@ pub fn fs_kind(metadata: &Metadata) -> FsKind {
|
||||||
"fuse.gvfsd-fuse" => FsKind::Gvfs,
|
"fuse.gvfsd-fuse" => FsKind::Gvfs,
|
||||||
_ => FsKind::Local,
|
_ => FsKind::Local,
|
||||||
};
|
};
|
||||||
devices.insert(dev, kind);
|
Some((dev, kind))
|
||||||
}
|
}));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("failed to get mount info: {err}");
|
log::warn!("failed to get mount info: {err}");
|
||||||
|
|
@ -2525,7 +2518,7 @@ impl Tab {
|
||||||
location: Location,
|
location: Location,
|
||||||
config: TabConfig,
|
config: TabConfig,
|
||||||
thumb_config: ThumbCfg,
|
thumb_config: ThumbCfg,
|
||||||
sorting_options: Option<&OrderMap<String, (HeadingOptions, bool)>>,
|
sorting_options: Option<&FxOrderMap<String, (HeadingOptions, bool)>>,
|
||||||
scrollable_id: widget::Id,
|
scrollable_id: widget::Id,
|
||||||
window_id: Option<window::Id>,
|
window_id: Option<window::Id>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use md5::{Digest, Md5};
|
use md5::{Digest, Md5};
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
error::Error,
|
error::Error,
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, BufReader, BufWriter},
|
io::{self, BufReader, BufWriter},
|
||||||
|
|
@ -143,7 +143,7 @@ impl ThumbnailCacher {
|
||||||
let mut reader = decoder.read_info()?;
|
let mut reader = decoder.read_info()?;
|
||||||
let (width, height, color_type, bit_depth, mut text_chunks) = {
|
let (width, height, color_type, bit_depth, mut text_chunks) = {
|
||||||
let info = reader.info();
|
let info = reader.info();
|
||||||
let text_chunks: HashMap<String, String> = info
|
let text_chunks: FxHashMap<String, String> = info
|
||||||
.uncompressed_latin1_text
|
.uncompressed_latin1_text
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use mime_guess::Mime;
|
use mime_guess::Mime;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
fs,
|
fs,
|
||||||
path::Path,
|
path::Path,
|
||||||
process,
|
process,
|
||||||
|
|
@ -56,13 +56,13 @@ impl Thumbnailer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ThumbnailerCache {
|
pub struct ThumbnailerCache {
|
||||||
cache: HashMap<Mime, Vec<Thumbnailer>>,
|
cache: FxHashMap<Mime, Vec<Thumbnailer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThumbnailerCache {
|
impl ThumbnailerCache {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut thumbnailer_cache = Self {
|
let mut thumbnailer_cache = Self {
|
||||||
cache: HashMap::new(),
|
cache: FxHashMap::default(),
|
||||||
};
|
};
|
||||||
thumbnailer_cache.reload();
|
thumbnailer_cache.reload();
|
||||||
thumbnailer_cache
|
thumbnailer_cache
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue