diff --git a/crates/color/src/lib.rs b/crates/color/src/lib.rs index 8e9f98d9..e2ca7016 100644 --- a/crates/color/src/lib.rs +++ b/crates/color/src/lib.rs @@ -122,7 +122,8 @@ impl Color { /// Parse hex the way the colour field does: `#` optional, 1, 2, 3, 4, 6 or 8 digits /// (`F` → `FFFFFF`, `AB` → `ABABAB`, `ABC` → `AABBCC`). pub fn from_hex(s: &str) -> Option { - let s = s.trim().trim_start_matches('#'); + let s = s.trim(); + let s = s.strip_prefix('#').unwrap_or(s); if !s.chars().all(|c| c.is_ascii_hexdigit()) { return None; } diff --git a/crates/color/src/tests.rs b/crates/color/src/tests.rs index 4cf875bb..fdec5b56 100644 --- a/crates/color/src/tests.rs +++ b/crates/color/src/tests.rs @@ -114,3 +114,12 @@ fn infinite_channels_clamp() { let c = Color::new(f32::INFINITY, f32::NEG_INFINITY, f32::NAN, f32::INFINITY); assert_eq!((c.r, c.g, c.b, c.a), (1.0, 0.0, 0.0, 1.0)); } + +#[test] +fn hex_allows_at_most_one_leading_hash() { + assert!(Color::from_hex("##ff0000").is_none()); + assert!(Color::from_hex("###fff").is_none()); + assert!(Color::from_hex_or_name("##ff0000").is_none()); + assert_eq!(Color::from_hex("#ff0000").unwrap().to_hex(), "FF0000"); + assert_eq!(Color::from_hex("ff0000").unwrap().to_hex(), "FF0000"); +}