From 143b744899ac6dd391a66b9decc41a66a853368a Mon Sep 17 00:00:00 2001 From: John Whittington Date: Wed, 3 Jul 2024 15:53:25 +0200 Subject: [PATCH] icon name pattern matching optional but default with F=regex_icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing with hyperfine [1], the icon pattern matching with the one default 'SD Card Reader' pattern seems to increase runtime by ~35%. Sounds large but we are talking in < 5 ms region for runs so this is perhaps 2 ms. I think the performance hit is worth it so will make default but feature can be disabled by removing 'regex_icon'. Also useful as a crate to avoid the added regex dependency. Worth point out that even with the feature enabled, if there are no `Icon::Name` in the theme, the performance is not impacted. [1] `hyperfine -N --warmup 3 'cyme --from-json ./tests/data/cyme_libusb_merge_macos_tree.json' '/Users/john/.cargo/target/release/cyme --from-json ./tests/data/cyme_libusb_merge_macos_tree.json'` Summary cyme --from-json ./tests/data/cyme_libusb_merge_macos_tree.json ran 1.35 ± 0.12 times faster than /Users/john/.cargo/target/release/cyme --from-json ./tests/data/cyme_libusb_merge_macos_tree.json --- Cargo.toml | 5 +++-- src/config.rs | 1 + src/icon.rs | 56 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e7db567..f7c9e00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ rand = "0.8.5" terminal_size = "0.2.5" strum = "0.24.1" strum_macros = "0.24.3" -regex = "1.10.5" +regex = { version = "1.10.5", optional = true } [dev-dependencies] diff = "0.1" @@ -59,8 +59,9 @@ udev_hwdb = ["libusb", "udevlib?/hwdb"] # libudev C binding udevlib = ["libusb", "dep:udevlib"] usb_test = [] +regex_icon = ["dep:regex"] cli_generate = ["dep:clap_complete", "dep:clap_mangen"] # for generating man and completions -default = ["libusb", "udev"] +default = ["libusb", "udev", "regex_icon"] [[bin]] name = "cyme" diff --git a/src/config.rs b/src/config.rs index 94d7956..b17de1f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -154,6 +154,7 @@ mod tests { use super::*; #[test] + #[cfg(feature = "regex")] fn test_deserialize_example_file() { let path = PathBuf::from("./doc").join("cyme_example_config.json"); assert!(Config::from_file(path).is_ok()); diff --git a/src/icon.rs b/src/icon.rs index 3d67b2e..e88ac9a 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -1,4 +1,5 @@ //! Icons and themeing of cyme output +#[cfg(feature = "regex_icon")] use regex; use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; @@ -91,13 +92,22 @@ impl FromStr for Icon { } // name#pattern } else if matches!(enum_name, "name") { + #[cfg(feature = "regex_icon")] match regex::Regex::new(value_split[1]) { Ok(_) => Ok(Icon::Name(value_split[1].to_string())), Err(_) => Err(Error::new( ErrorKind::Parsing, - "Invalid regex pattern in Icon enum string", + &format!( + "Invalid regex pattern in Icon::Name enum string: {}", + value_split[1] + ), )), } + #[cfg(not(feature = "regex_icon"))] + Err(Error::new( + ErrorKind::Parsing, + "regex_icon feature not enabled for Icon::Name matching", + )) // enum contains value } else { let (parse_ints, errors): (Vec>, Vec<_>) = value_split[1] @@ -276,6 +286,7 @@ lazy_static! { (Icon::Vid(0x1fc9), "\u{f2db}"), // nxp  (Icon::Vid(0x1050), "\u{f084}"), // yubikey  (Icon::Vid(0x0781), "\u{f129e}"), // sandisk 󱊞 + #[cfg(feature = "regex_icon")] (Icon::Name(r".*^[sS][dD]\s[cC]ard\s[rR]eader.*".to_string()), "\u{ef61}"), // sd card reader  (Icon::VidPid((0x18D1, 0x2D05)), "\u{e70e}"), // android dev  (Icon::VidPid((0x18D1, 0xd00d)), "\u{e70e}"), // android  @@ -378,6 +389,7 @@ impl IconTheme { } /// Get icon for USBDevice `d` by checking `Self` using Name, Vendor ID and Product ID + #[cfg(feature = "regex_icon")] pub fn get_device_icon(&self, d: &USBDevice) -> String { // try name first since vidpid will return UnknownVendor default icon if not found // does mean regex will be built/checked for every device @@ -393,6 +405,16 @@ impl IconTheme { } } + /// Get icon for USBDevice `d` by checking `Self` using Vendor ID and Product ID + #[cfg(not(feature = "regex_icon"))] + pub fn get_device_icon(&self, d: &USBDevice) -> String { + if let (Some(vid), Some(pid)) = (d.vendor_id, d.product_id) { + self.get_vidpid_icon(vid, pid) + } else { + String::new() + } + } + /// Get icon for USBBus `d` by checking `Self` using PCI Vendor and PCI Device pub fn get_bus_icon(&self, d: &USBBus) -> String { if let (Some(vid), Some(pid)) = (d.pci_vendor, d.pci_device) { @@ -442,6 +464,7 @@ impl IconTheme { } /// Get default icon for device based on descriptor name pattern `[Icon::Name]` pattern match + #[cfg(feature = "regex_icon")] pub fn get_default_name_icon(name: &str) -> String { DEFAULT_ICONS .iter() @@ -458,6 +481,7 @@ impl IconTheme { } /// Get icon for device based on descriptor name pattern `[Icon::Name]` pattern match + #[cfg(feature = "regex_icon")] pub fn get_name_icon(&self, name: &str) -> String { if let Some(user_icons) = self.user.as_ref() { user_icons @@ -512,6 +536,7 @@ pub fn example() -> HashMap { "\u{e795}".into(), ), // serial  (Icon::UndefinedClassifier, "\u{2636}".into()), //☶ + #[cfg(feature = "regex_icon")] ( Icon::Name(r".*^[sS][dD]\s[cC]ard\s[rR]eader.*".to_string()), "\u{ef61}".into(), @@ -620,21 +645,24 @@ mod tests { let icon = Icon::from_str(str); assert_eq!(icon.unwrap(), Icon::UnknownVendor); - let str = "name#test"; - let icon = Icon::from_str(str); - assert_eq!(icon.unwrap(), Icon::Name("test".to_string())); - - let str = r"name#.*^[sS][dD]\s[cC]ard\s[rR]eader.*"; - let icon = Icon::from_str(str); - assert_eq!( - icon.unwrap(), - Icon::Name(r".*^[sS][dD]\s[cC]ard\s[rR]eader.*".to_string()) - ); + if cfg!(feature = "regex_icon") { + let str = "name#test"; + let icon = Icon::from_str(str); + assert_eq!(icon.unwrap(), Icon::Name("test".to_string())); + + let str = r"name#.*^[sS][dD]\s[cC]ard\s[rR]eader.*"; + let icon = Icon::from_str(str); + assert_eq!( + icon.unwrap(), + Icon::Name(r".*^[sS][dD]\s[cC]ard\s[rR]eader.*".to_string()) + ); + } } #[test] + #[cfg(feature = "regex_icon")] fn icon_match_name() { - let device = USBDevice { + let mut device = USBDevice { name: "SD Card Reader".to_string(), ..Default::default() }; @@ -649,5 +677,9 @@ mod tests { let icon = theme.get_device_icon(&device); assert_eq!(icon, "\u{ef61}"); + + device.name = "sD Card reader 2".to_string(); + let icon = theme.get_device_icon(&device); + assert_eq!(icon, "\u{ef61}"); } }