1use crate::Srgb;
2use core::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct Hex(u32);
7
8const fn is_shorthand_byte(byte: u8) -> bool {
9 (byte >> 4) == (byte & 0xF)
10}
11
12impl Hex {
13 pub const fn new(hex: u32) -> Self {
14 Self(hex)
15 }
16
17 pub fn can_use_3_digit(self) -> bool {
18 let Srgb { red, green, blue, .. } = self.into();
19 !self.has_alpha() && is_shorthand_byte(red) && is_shorthand_byte(green) && is_shorthand_byte(blue)
20 }
21
22 pub fn can_use_4_digit(self) -> bool {
23 let Srgb { red, green, blue, alpha } = self.into();
24 is_shorthand_byte(red)
25 && is_shorthand_byte(green)
26 && is_shorthand_byte(blue)
27 && is_shorthand_byte(((alpha as u32 * 255) / 100) as u8)
28 }
29
30 pub const fn has_alpha(&self) -> bool {
31 self.0 & 0xFF != 0xFF
32 }
33}
34
35impl fmt::Display for Hex {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 let Srgb { red, green, blue, alpha } = (*self).into();
38 let alpha = (alpha as u32 * 255) / 100;
39 if self.can_use_3_digit() {
40 write!(f, "#{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF)
41 } else if self.can_use_4_digit() {
42 write!(f, "#{:x}{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF, alpha & 0xF)
43 } else if self.has_alpha() {
44 write!(f, "#{red:02x}{green:02x}{blue:02x}{alpha:02x}")
45 } else {
46 write!(f, "#{red:02x}{green:02x}{blue:02x}")
47 }
48 }
49}
50
51impl From<Hex> for Srgb {
52 fn from(value: Hex) -> Self {
53 let hex = value.0;
54 let r = ((hex >> 24) & 0xFF) as u8;
55 let g = ((hex >> 16) & 0xFF) as u8;
56 let b = ((hex >> 8) & 0xFF) as u8;
57 let alpha = (((hex & 0xFF) * 100) / 255) as f32;
58 Srgb::new(r, g, b, alpha)
59 }
60}
61
62impl From<Srgb> for Hex {
63 fn from(value: Srgb) -> Self {
64 let Srgb { red, green, blue, alpha } = value;
65 Hex::new(((red as u32) << 24) | ((green as u32) << 16) | ((blue as u32) << 8) | ((alpha as u32 * 255) / 100))
66 }
67}