use crate::{Srgb, ToAlpha};
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Hex(u32);
const fn is_shorthand_byte(byte: u8) -> bool {
(byte >> 4) == (byte & 0xF)
}
impl Hex {
pub const fn new(hex: u32) -> Self {
Self(hex)
}
pub fn can_use_3_digit(self) -> bool {
let Srgb { red, green, blue, .. } = self.into();
!self.has_alpha() && is_shorthand_byte(red) && is_shorthand_byte(green) && is_shorthand_byte(blue)
}
pub fn can_use_4_digit(self) -> bool {
let Srgb { red, green, blue, alpha } = self.into();
is_shorthand_byte(red)
&& is_shorthand_byte(green)
&& is_shorthand_byte(blue)
&& is_shorthand_byte((alpha * 255.0 / 100.0).round() as u8)
}
pub const fn has_alpha(&self) -> bool {
self.0 & 0xFF != 0xFF
}
}
impl ToAlpha for Hex {
fn to_alpha(&self) -> f32 {
((self.0 & 0xFF) as f32 / 255.0) * 100.0
}
}
impl fmt::Display for Hex {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Srgb { red, green, blue, alpha } = (*self).into();
let alpha = (alpha * 255.0 / 100.0).round() as u32;
if self.can_use_3_digit() {
write!(f, "#{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF)
} else if self.can_use_4_digit() {
write!(f, "#{:x}{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF, alpha & 0xF)
} else if self.has_alpha() {
write!(f, "#{red:02x}{green:02x}{blue:02x}{alpha:02x}")
} else {
write!(f, "#{red:02x}{green:02x}{blue:02x}")
}
}
}
impl From<Hex> for Srgb {
fn from(value: Hex) -> Self {
let hex = value.0;
let r = ((hex >> 24) & 0xFF) as u8;
let g = ((hex >> 16) & 0xFF) as u8;
let b = ((hex >> 8) & 0xFF) as u8;
let alpha = (((hex & 0xFF) * 100) / 255) as f32;
Srgb::new(r, g, b, alpha)
}
}
impl From<Srgb> for Hex {
fn from(value: Srgb) -> Self {
let Srgb { red, green, blue, alpha } = value;
Hex::new(
((red as u32) << 24)
| ((green as u32) << 16)
| ((blue as u32) << 8)
| ((alpha * 255.0 / 100.0).round() as u32),
)
}
}