#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HexColor {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl HexColor {
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b }
}
pub fn parse(s: &str) -> Result<Self, &'static str> {
let s = s.strip_prefix('#').ok_or("missing '#' prefix")?;
if s.len() != 6 {
return Err("expected 6 hex digits");
}
let r = u8::from_str_radix(&s[0..2], 16).map_err(|_| "invalid red")?;
let g = u8::from_str_radix(&s[2..4], 16).map_err(|_| "invalid green")?;
let b = u8::from_str_radix(&s[4..6], 16).map_err(|_| "invalid blue")?;
Ok(Self { r, g, b })
}
pub fn to_hex_string(&self) -> String {
format!("#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
}
}
impl std::fmt::Display for HexColor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_hex_string())
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::HexColor;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
impl<'de> Deserialize<'de> for HexColor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
HexColor::parse(&s).map_err(serde::de::Error::custom)
}
}
impl Serialize for HexColor {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_hex_string())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let c = HexColor::parse("#532746").unwrap();
assert_eq!(c.to_hex_string(), "#532746");
}
}