chromashift/
hex.rs

1use crate::Srgb;
2use core::fmt;
3
4/// An Hex representation of the sRGB colour space.
5#[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}