1use crate::{Srgb, ToAlpha};
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 [red, green, blue, _] = self.0.to_be_bytes();
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 [red, green, blue, alpha] = self.0.to_be_bytes();
24 is_shorthand_byte(red) && is_shorthand_byte(green) && is_shorthand_byte(blue) && is_shorthand_byte(alpha)
25 }
26
27 pub const fn has_alpha(&self) -> bool {
28 self.0 & 0xFF != 0xFF
29 }
30}
31
32impl ToAlpha for Hex {
33 fn to_alpha(&self) -> f32 {
34 ((self.0 & 0xFF) as f32 / 255.0) * 100.0
35 }
36}
37
38impl fmt::Display for Hex {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 let [red, green, blue, alpha] = self.0.to_be_bytes();
41 if self.can_use_3_digit() {
42 write!(f, "#{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF)
43 } else if self.can_use_4_digit() {
44 write!(f, "#{:x}{:x}{:x}{:x}", red & 0xF, green & 0xF, blue & 0xF, alpha & 0xF)
45 } else if self.has_alpha() {
46 write!(f, "#{red:02x}{green:02x}{blue:02x}{alpha:02x}")
47 } else {
48 write!(f, "#{red:02x}{green:02x}{blue:02x}")
49 }
50 }
51}
52
53impl From<Hex> for Srgb {
54 fn from(value: Hex) -> Self {
55 let [red, green, blue, alpha] = value.0.to_be_bytes();
56 Srgb::from_u8(red, green, blue, alpha as f32 * 100.0 / 255.0)
57 }
58}
59
60impl From<Srgb> for Hex {
61 fn from(value: Srgb) -> Self {
62 let [red, green, blue] = value.to_u8();
63 let alpha = value.alpha;
64 Hex::new(
65 ((red as u32) << 24)
66 | ((green as u32) << 16)
67 | ((blue as u32) << 8)
68 | ((alpha * 255.0 / 100.0).round() as u32),
69 )
70 }
71}