From 3a83bd31ab165869f7f274b054b2f16485261fd1 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sat, 5 Nov 2022 17:32:01 +0000 Subject: [PATCH] fix: able to insert duplicate keys into collection This replaces the custom `Collection` implementation with `IndexMap` from the crate of the same name. Fixes #28. --- Cargo.lock | 1 + Cargo.toml | 5 +- src/collection.rs | 161 ----------------------------------- src/main.rs | 1 - src/modules/focused.rs | 4 +- src/modules/launcher/item.rs | 12 +-- src/modules/launcher/mod.rs | 20 ++--- src/wayland/client.rs | 5 +- 8 files changed, 24 insertions(+), 185 deletions(-) delete mode 100644 src/collection.rs diff --git a/Cargo.lock b/Cargo.lock index 692f255..d964975 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1146,6 +1146,7 @@ dependencies = [ "glib", "gtk", "gtk-layer-shell", + "indexmap", "lazy_static", "libcorn", "mpd_client", diff --git a/Cargo.toml b/Cargo.toml index 2e793d7..50057c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,6 @@ tracing-error = "0.2.0" tracing-appender = "0.2.2" strip-ansi-escapes = "0.1.1" color-eyre = "0.6.2" -futures-util = "0.3.21" -chrono = "0.4.19" serde = { version = "1.0.141", features = ["derive"] } serde_json = "1.0.82" serde_yaml = "0.9.4" @@ -26,6 +24,9 @@ toml = "0.5.9" libcorn = "0.4.0" lazy_static = "1.4.0" async_once = "0.2.6" +indexmap = "1.9.1" +futures-util = "0.3.21" +chrono = "0.4.19" regex = { version = "1.6.0", default-features = false, features = ["std"] } stray = { version = "0.1.2" } dirs = "4.0.0" diff --git a/src/collection.rs b/src/collection.rs deleted file mode 100644 index ce19f3c..0000000 --- a/src/collection.rs +++ /dev/null @@ -1,161 +0,0 @@ -use serde::Serialize; -use std::slice::{Iter, IterMut}; -use std::vec; - -/// An ordered map. -/// Internally this is just two vectors - -/// one for keys and one for values. -#[derive(Debug, Clone, Serialize)] -pub struct Collection { - keys: Vec, - values: Vec, -} - -impl Collection { - /// Creates a new empty collection. - pub const fn new() -> Self { - Self { - keys: vec![], - values: vec![], - } - } - - /// Inserts a new key/value pair at the end of the collection. - pub fn insert(&mut self, key: TKey, value: TData) { - self.keys.push(key); - self.values.push(value); - - assert_eq!(self.keys.len(), self.values.len()); - } - - /// Gets a reference of the value for the specified key - /// if it exists in the collection. - pub fn get(&self, key: &TKey) -> Option<&TData> { - let index = self.keys.iter().position(|k| k == key); - match index { - Some(index) => self.values.get(index), - None => None, - } - } - - /// Gets a mutable reference for the value with the specified key - /// if it exists in the collection. - pub fn get_mut(&mut self, key: &TKey) -> Option<&mut TData> { - let index = self.keys.iter().position(|k| k == key); - match index { - Some(index) => self.values.get_mut(index), - None => None, - } - } - - /// Checks if a value for the given key exists inside the collection - pub fn contains(&self, key: &TKey) -> bool { - self.keys.contains(key) - } - - /// Removes the key/value from the collection - /// if it exists - /// and returns the removed value. - pub fn remove(&mut self, key: &TKey) -> Option { - assert_eq!(self.keys.len(), self.values.len()); - - let index = self.keys.iter().position(|k| k == key); - if let Some(index) = index { - self.keys.remove(index); - Some(self.values.remove(index)) - } else { - None - } - } - - /// Gets the length of the collection. - pub fn len(&self) -> usize { - self.keys.len() - } - - /// Gets a reference to the first value in the collection. - pub fn first(&self) -> Option<&TData> { - self.values.first() - } - - /// Gets the values as a slice. - pub fn as_slice(&self) -> &[TData] { - self.values.as_slice() - } - - /// Checks whether the collection is empty. - pub fn is_empty(&self) -> bool { - self.keys.is_empty() - } - - /// Gets an iterator for the collection. - pub fn iter(&self) -> Iter<'_, TData> { - self.values.iter() - } - - /// Gets a mutable iterator for the collection - pub fn iter_mut(&mut self) -> IterMut<'_, TData> { - self.values.iter_mut() - } -} - -impl From<(TKey, TData)> for Collection { - fn from((key, value): (TKey, TData)) -> Self { - let mut collection = Self::new(); - collection.insert(key, value); - collection - } -} - -impl FromIterator<(TKey, TData)> for Collection { - fn from_iter>(iter: T) -> Self { - let mut collection = Self::new(); - for (key, value) in iter { - collection.insert(key, value); - } - - collection - } -} - -impl<'a, TKey: PartialEq, TData> IntoIterator for &'a Collection { - type Item = &'a TData; - type IntoIter = CollectionIntoIterator<'a, TKey, TData>; - - fn into_iter(self) -> Self::IntoIter { - CollectionIntoIterator { - collection: self, - index: 0, - } - } -} - -pub struct CollectionIntoIterator<'a, TKey, TData> { - collection: &'a Collection, - index: usize, -} - -impl<'a, TKey: PartialEq, TData> Iterator for CollectionIntoIterator<'a, TKey, TData> { - type Item = &'a TData; - - fn next(&mut self) -> Option { - let res = self.collection.values.get(self.index); - self.index += 1; - res - } -} - -impl Default for Collection { - fn default() -> Self { - Self::new() - } -} - -impl IntoIterator for Collection { - type Item = TData; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.values.into_iter() - } -} diff --git a/src/main.rs b/src/main.rs index 311c5f6..edfd55b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,5 @@ mod bar; mod bridge_channel; -mod collection; mod config; mod icon; mod logging; diff --git a/src/modules/focused.rs b/src/modules/focused.rs index fa2e2cc..3ce66bf 100644 --- a/src/modules/focused.rs +++ b/src/modules/focused.rs @@ -47,10 +47,10 @@ impl Module for FocusedModule { .expect("Failed to get read lock on toplevels") .clone(); - toplevels.into_iter().find(|(top, _)| top.active) + toplevels.into_iter().find(|(_, (top, _))| top.active) }); - if let Some((top, _)) = focused { + if let Some((_, (top, _))) = focused { tx.try_send(ModuleUpdateEvent::Update((top.title.clone(), top.app_id)))?; } diff --git a/src/modules/launcher/item.rs b/src/modules/launcher/item.rs index a959d6c..731f341 100644 --- a/src/modules/launcher/item.rs +++ b/src/modules/launcher/item.rs @@ -1,5 +1,4 @@ use super::open_state::OpenState; -use crate::collection::Collection; use crate::icon::get_icon; use crate::modules::launcher::{ItemEvent, LauncherUpdate}; use crate::modules::ModuleUpdateEvent; @@ -7,6 +6,7 @@ use crate::popup::Popup; use crate::wayland::ToplevelInfo; use gtk::prelude::*; use gtk::{Button, IconTheme, Image, Orientation}; +use indexmap::IndexMap; use std::rc::Rc; use std::sync::RwLock; use tokio::sync::mpsc::Sender; @@ -16,17 +16,17 @@ pub struct Item { pub app_id: String, pub favorite: bool, pub open_state: OpenState, - pub windows: Collection, + pub windows: IndexMap, pub name: String, } impl Item { - pub const fn new(app_id: String, open_state: OpenState, favorite: bool) -> Self { + pub fn new(app_id: String, open_state: OpenState, favorite: bool) -> Self { Self { app_id, favorite, open_state, - windows: Collection::new(), + windows: IndexMap::new(), name: String::new(), } } @@ -78,7 +78,7 @@ impl Item { &self .windows .iter() - .map(|win| &win.open_state) + .map(|(_, win)| &win.open_state) .collect::>(), ); self.open_state = new_state; @@ -91,7 +91,7 @@ impl From for Item { let name = toplevel.title.clone(); let app_id = toplevel.app_id.clone(); - let mut windows = Collection::new(); + let mut windows = IndexMap::new(); windows.insert(toplevel.id, toplevel.into()); Self { diff --git a/src/modules/launcher/mod.rs b/src/modules/launcher/mod.rs index 6dcfc70..5968bda 100644 --- a/src/modules/launcher/mod.rs +++ b/src/modules/launcher/mod.rs @@ -3,7 +3,6 @@ mod open_state; use self::item::{Item, ItemButton, Window}; use self::open_state::OpenState; -use crate::collection::Collection; use crate::icon::find_desktop_file; use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext}; use crate::wayland; @@ -12,6 +11,7 @@ use color_eyre::{Help, Report}; use glib::Continue; use gtk::prelude::*; use gtk::{Button, IconTheme, Orientation}; +use indexmap::IndexMap; use serde::Deserialize; use std::process::{Command, Stdio}; use std::sync::{Arc, Mutex}; @@ -90,8 +90,8 @@ impl Module for LauncherModule { Item::new(app_id.to_string(), OpenState::Closed, true), ) }) - .collect::>(), - None => Collection::new(), + .collect::>(), + None => IndexMap::new(), }; let items = Arc::new(Mutex::new(items)); @@ -108,7 +108,7 @@ impl Module for LauncherModule { let mut items = items.lock().expect("Failed to get lock on items"); - for (window, _) in open_windows.clone() { + for (_, (window, _)) in open_windows.clone() { let item = items.get_mut(&window.app_id); match item { Some(item) => { @@ -121,7 +121,7 @@ impl Module for LauncherModule { } let items = items.iter(); - for item in items { + for (_, item) in items { tx.try_send(ModuleUpdateEvent::Update(LauncherUpdate::AddItem( item.clone(), )))?; @@ -282,7 +282,7 @@ impl Module for LauncherModule { let id = match event { ItemEvent::FocusItem(app_id) => items .get(&app_id) - .and_then(|item| item.windows.first().map(|win| win.id)), + .and_then(|item| item.windows.first().map(|(_, win)| win.id)), ItemEvent::FocusWindow(id) => Some(id), ItemEvent::OpenItem(_) => unreachable!(), }; @@ -325,7 +325,7 @@ impl Module for LauncherModule { let show_icons = self.show_icons; let orientation = info.bar_position.get_orientation(); - let mut buttons = Collection::::new(); + let mut buttons = IndexMap::::new(); let controller_tx2 = context.controller_tx.clone(); context.widget_rx.attach(None, move |event| { @@ -431,7 +431,7 @@ impl Module for LauncherModule { placeholder.set_width_request(MAX_WIDTH); container.add(&placeholder); - let mut buttons = Collection::>::new(); + let mut buttons = IndexMap::>::new(); { let container = container.clone(); @@ -443,7 +443,7 @@ impl Module for LauncherModule { let window_buttons = item .windows .into_iter() - .map(|win| { + .map(|(_, win)| { let button = Button::builder() .label(&clamp(&win.name)) .height_request(40) @@ -509,7 +509,7 @@ impl Module for LauncherModule { // add app's buttons if let Some(buttons) = buttons.get(&app_id) { - for button in buttons { + for (_, button) in buttons { button.style_context().add_class("popup-item"); container.add(button); } diff --git a/src/wayland/client.rs b/src/wayland/client.rs index 9763d9e..afeed12 100644 --- a/src/wayland/client.rs +++ b/src/wayland/client.rs @@ -1,5 +1,4 @@ use super::{Env, ToplevelHandler}; -use crate::collection::Collection; use crate::wayland::toplevel::{ToplevelEvent, ToplevelInfo}; use crate::wayland::toplevel_manager::listen_for_toplevels; use crate::wayland::ToplevelChange; @@ -21,7 +20,7 @@ use wayland_protocols::wlr::unstable::foreign_toplevel::v1::client::{ pub struct WaylandClient { pub outputs: Vec, pub seats: Vec, - pub toplevels: Arc>>, + pub toplevels: Arc>>, toplevel_tx: broadcast::Sender, _toplevel_rx: broadcast::Receiver, } @@ -35,7 +34,7 @@ impl WaylandClient { let toplevel_tx2 = toplevel_tx.clone(); - let toplevels = Arc::new(RwLock::new(Collection::new())); + let toplevels = Arc::new(RwLock::new(IndexMap::new())); let toplevels2 = toplevels.clone(); // `queue` is not send so we need to handle everything inside the task