From 570144ee90e217da2ef27c1c5a4e839f6f0c06df Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:49:45 +0000 Subject: [PATCH] Reject multiple leading '#' in Color::from_hex Found while testing crates/color/src/lib.rs:125 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/color/src/lib.rs | 3 ++- crates/color/src/tests.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) 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"); +}