#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SvgColor {
None,
Rgb(u8, u8, u8),
}
impl SvgColor {
pub fn parse(value: &str) -> SvgColor {
let v = value.trim();
if v.is_empty() || v.eq_ignore_ascii_case("none") || v.eq_ignore_ascii_case("transparent") {
return SvgColor::None;
}
if let Some(hex) = v.strip_prefix('#') {
if hex.len() == 3 {
if let (Ok(r), Ok(g), Ok(b)) = (
u8::from_str_radix(&hex[0..1], 16),
u8::from_str_radix(&hex[1..2], 16),
u8::from_str_radix(&hex[2..3], 16),
) {
return SvgColor::Rgb(r * 17, g * 17, b * 17);
}
} else if hex.len() == 6 {
if let Ok(v) = u32::from_str_radix(hex, 16) {
return SvgColor::Rgb((v >> 16) as u8, (v >> 8) as u8, v as u8);
}
} else if hex.len() == 8 {
if let Ok(v) = u32::from_str_radix(&hex[0..6], 16) {
return SvgColor::Rgb((v >> 16) as u8, (v >> 8) as u8, v as u8);
}
}
return SvgColor::Rgb(0, 0, 0);
}
let named = match v.to_ascii_lowercase().as_str() {
"black" => Some((0, 0, 0)),
"white" => Some((255, 255, 255)),
"red" => Some((255, 0, 0)),
"aqua" | "cyan" => Some((0, 255, 255)),
"magenta" => Some((255, 0, 255)),
"yellow" => Some((255, 255, 0)),
"gray" | "grey" => Some((128, 128, 128)),
"silver" => Some((192, 192, 192)),
"blue" => Some((0, 0, 255)),
"green" => Some((0, 128, 0)),
"orange" => Some((255, 165, 0)),
"purple" => Some((128, 0, 128)),
_ => None,
};
match named {
Some((r, g, b)) => SvgColor::Rgb(r, g, b),
None => SvgColor::Rgb(0, 0, 0), }
}
pub fn is_none(&self) -> bool {
matches!(self, SvgColor::None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_hex() {
assert_eq!(SvgColor::parse("#fff"), SvgColor::Rgb(255, 255, 255));
assert_eq!(SvgColor::parse("#884f00"), SvgColor::Rgb(0x88, 0x4f, 0x00));
assert_eq!(SvgColor::parse("#000"), SvgColor::Rgb(0, 0, 0));
}
#[test]
fn parse_named_and_none() {
assert_eq!(SvgColor::parse("black"), SvgColor::Rgb(0, 0, 0));
assert_eq!(SvgColor::parse("none"), SvgColor::None);
assert_eq!(SvgColor::parse(""), SvgColor::None);
assert_eq!(SvgColor::parse("transparent"), SvgColor::None);
}
}