From 5b79f267d615e671b8ac9874c16d927d06dca8eb Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 7 May 2024 12:53:44 -0500 Subject: [PATCH] Optimize color::try_parse_rgb() The function was repeatedly calling `s.char_at(n)` which is O(1) only for UTF-32 strings (so not a problem at the moment). But it was also calling `hex_digit(n)` twice for each `n` in the 3-digit case, causing unnecessary repeated parsing of individual characters into their radix-16 numeric equivalents, which could be avoided just by reusing the already calculated result. --- src/color.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/color.rs b/src/color.rs index fa48dd1f8..a0454713d 100644 --- a/src/color.rs +++ b/src/color.rs @@ -257,34 +257,36 @@ impl RgbColor { /// - `FA3` /// - `F3A035` + /// Parses input in the form of `#RGB` or `#RRGGBB` with an optional single leading `#` into + /// an instance of [`RgbColor`]. + /// + /// Returns `None` if the input contains invalid hexadecimal characters or is not in the + /// expected `#RGB` or `#RRGGBB` formats. fn try_parse_rgb(mut s: &wstr) -> Option { - // Skip any leading #. + // Skip one leading # if s.chars().next()? == '#' { s = &s[1..]; } - let hex_digit = |i| -> Option { - s.char_at(i) - .to_digit(16) - .map(|n| n.try_into().expect("hex digit should always be < 256")) - }; + let mut hex = s.chars().map_while(|c| c.to_digit(16).map(|b| b as u8)); - let r; - let g; - let b; - if s.len() == 3 { - // Format: FA3 - r = hex_digit(0)? * 16 + hex_digit(0)?; - g = hex_digit(1)? * 16 + hex_digit(1)?; - b = hex_digit(2)? * 16 + hex_digit(2)?; + let (r, g, b) = if s.len() == 3 { + // Expected format: FA3 + ( + hex.next().map(|d| d * 16 + d)?, + hex.next().map(|d| d * 16 + d)?, + hex.next().map(|d| d * 16 + d)?, + ) } else if s.len() == 6 { - // Format: F3A035 - r = hex_digit(0)? * 16 + hex_digit(1)?; - g = hex_digit(2)? * 16 + hex_digit(3)?; - b = hex_digit(4)? * 16 + hex_digit(5)?; + // Expected format: F3A035 + ( + hex.next()? * 16 + hex.next()?, + hex.next()? * 16 + hex.next()?, + hex.next()? * 16 + hex.next()?, + ) } else { return None; - } + }; Some(RgbColor::from_rgb(r, g, b)) }