summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/src/color.rs94
1 files changed, 43 insertions, 51 deletions
diff --git a/core/src/color.rs b/core/src/color.rs
index 4f4b5e9b..89ec0e5b 100644
--- a/core/src/color.rs
+++ b/core/src/color.rs
@@ -1,13 +1,5 @@
use palette::rgb::{Srgb, Srgba};
-#[derive(Debug, thiserror::Error)]
-/// Errors that can occur when constructing a [`Color`].
-pub enum ColorError {
- #[error("The specified hex string is invalid. See supported formats.")]
- /// The specified hex string is invalid. See supported formats.
- InvalidHex,
-}
-
/// A color in the `sRGB` color space.
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Color {
@@ -96,50 +88,46 @@ impl Color {
}
}
- /// Creates a [`Color`] from a hex string. Supported formats are #rrggbb, #rrggbbaa, #rgb,
- /// #rgba. The “#” is optional. Both uppercase and lowercase are supported.
- pub fn from_hex(s: &str) -> Result<Color, ColorError> {
+ /// Parses a [`Color`] from a hex string.
+ ///
+ /// Supported formats are #rrggbb, #rrggbbaa, #rgb, and #rgba.
+ /// The starting "#" is optional. Both uppercase and lowercase are supported.
+ pub fn parse(s: &str) -> Option<Color> {
let hex = s.strip_prefix('#').unwrap_or(s);
- let n_chars = hex.len();
- let get_channel = |from: usize, to: usize| {
- let num = usize::from_str_radix(&hex[from..=to], 16)
- .map_err(|_| ColorError::InvalidHex)?
- as f32
- / 255.0;
+ let parse_channel = |from: usize, to: usize| {
+ let num =
+ usize::from_str_radix(&hex[from..=to], 16).ok()? as f32 / 255.0;
+
// If we only got half a byte (one letter), expand it into a full byte (two letters)
- Ok(if from == to { num + num * 16.0 } else { num })
+ Some(if from == to { num + num * 16.0 } else { num })
};
- if n_chars == 3 {
- Ok(Color::from_rgb(
- get_channel(0, 0)?,
- get_channel(1, 1)?,
- get_channel(2, 2)?,
- ))
- } else if n_chars == 6 {
- Ok(Color::from_rgb(
- get_channel(0, 1)?,
- get_channel(2, 3)?,
- get_channel(4, 5)?,
- ))
- } else if n_chars == 4 {
- Ok(Color::from_rgba(
- get_channel(0, 0)?,
- get_channel(1, 1)?,
- get_channel(2, 2)?,
- get_channel(3, 3)?,
- ))
- } else if n_chars == 8 {
- Ok(Color::from_rgba(
- get_channel(0, 1)?,
- get_channel(2, 3)?,
- get_channel(4, 5)?,
- get_channel(6, 7)?,
- ))
- } else {
- Err(ColorError::InvalidHex)
- }
+ Some(match hex.len() {
+ 3 => Color::from_rgb(
+ parse_channel(0, 0)?,
+ parse_channel(1, 1)?,
+ parse_channel(2, 2)?,
+ ),
+ 4 => Color::from_rgba(
+ parse_channel(0, 0)?,
+ parse_channel(1, 1)?,
+ parse_channel(2, 2)?,
+ parse_channel(3, 3)?,
+ ),
+ 6 => Color::from_rgb(
+ parse_channel(0, 1)?,
+ parse_channel(2, 3)?,
+ parse_channel(4, 5)?,
+ ),
+ 8 => Color::from_rgba(
+ parse_channel(0, 1)?,
+ parse_channel(2, 3)?,
+ parse_channel(4, 5)?,
+ parse_channel(6, 7)?,
+ ),
+ _ => None?,
+ })
}
/// Creates a [`Color`] from its linear RGBA components.
@@ -360,17 +348,21 @@ mod tests {
}
#[test]
- fn from_hex() -> Result<(), ColorError> {
+ fn parse() {
let tests = [
("#ff0000", [255, 0, 0, 255]),
("00ff0080", [0, 255, 0, 128]),
("#F80", [255, 136, 0, 255]),
("#00f1", [0, 0, 255, 17]),
];
+
for (arg, expected) in tests {
- assert_eq!(Color::from_hex(arg)?.into_rgba8(), expected);
+ assert_eq!(
+ Color::parse(arg).expect("color must parse").into_rgba8(),
+ expected
+ );
}
- assert!(Color::from_hex("invalid").is_err());
- Ok(())
+
+ assert!(Color::parse("invalid").is_none());
}
}