Skip to content

Commit

Permalink
icon name pattern matching optional but default with F=regex_icon
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tuna-f1sh committed Jul 3, 2024
1 parent 3f0e954 commit 143b744
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 14 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
56 changes: 44 additions & 12 deletions src/icon.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<Result<u32, _>>, Vec<_>) = value_split[1]
Expand Down Expand Up @@ -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 
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -512,6 +536,7 @@ pub fn example() -> HashMap<Icon, String> {
"\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(),
Expand Down Expand Up @@ -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()
};
Expand All @@ -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}");
}
}

0 comments on commit 143b744

Please sign in to comment.