#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RGB(pub u8, pub u8, pub u8);
impl Default for RGB {
fn default() -> Self {
RGB(255, 255, 255)
}
}
impl std::fmt::Display for RGB {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(r, g, b) = self;
write!(f, "#{:02X}{:02X}{:02X}", r, g, b)
}
}
impl From<&str> for RGB {
fn from(s: &str) -> Self {
RGB::from_hex(s)
}
}
impl From<String> for RGB {
fn from(s: String) -> Self {
RGB::from_hex(&s)
}
}
impl RGB {
pub fn from_hex(input: &str) -> Self {
let input = input.trim();
let input = match (input.chars().next(), input.len()) {
(Some('#'), 7) => &input[1..],
(_, 6) => input,
_ => return Self::default(),
};
u32::from_str_radix(&input, 16)
.and_then(|s| {
Ok(RGB(
((s >> 16) & 0xFF) as u8,
((s >> 8) & 0xFF) as u8,
(s & 0xFF) as u8,
))
})
.unwrap_or_default()
}
pub fn red(self) -> u8 {
self.0
}
pub fn green(self) -> u8 {
self.1
}
pub fn blue(self) -> u8 {
self.2
}
}
impl From<Twitch> for RGB {
fn from(color: Twitch) -> Self {
if let Twitch::Turbo(rgb) = color {
return rgb;
}
twitch_colors()
.iter()
.find(|(c, _)| *c == color)
.map(|&(_, rgb)| rgb)
.unwrap_or_default()
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Twitch {
Blue,
BlueViolet,
CadetBlue,
Chocolate,
Coral,
DodgerBlue,
Firebrick,
GoldenRod,
Green,
HotPink,
OrangeRed,
Red,
SeaGreen,
SpringGreen,
YellowGreen,
Turbo(RGB),
}
impl Default for Twitch {
fn default() -> Self {
Twitch::Turbo(RGB::default())
}
}
impl From<&str> for Twitch {
fn from(input: &str) -> Self {
use Twitch::*;
match input {
"Blue" | "blue" => Blue,
"BlueViolet" | "blue_violet" | "blueviolet" | "blue violet" => BlueViolet,
"CadetBlue" | "cadet_blue" | "cadetblue" | "cadet blue" => CadetBlue,
"Chocolate" | "chocolate" => Chocolate,
"Coral" | "coral" => Coral,
"DodgerBlue" | "dodger_blue" | "dodgerblue" | "dodger blue" => DodgerBlue,
"Firebrick" | "firebrick" => Firebrick,
"GoldenRod" | "golden_rod" | "goldenrod" | "golden rod" => GoldenRod,
"Green" | "green" => Green,
"HotPink" | "hot_pink" | "hotpink" | "hot pink" => HotPink,
"OrangeRed" | "orange_red" | "orangered" | "orange red" => OrangeRed,
"Red" | "red" => Red,
"SeaGreen" | "sea_green" | "seagreen" | "sea green" => SeaGreen,
"SpringGreen" | "spring_green" | "springgreen" | "spring green" => SpringGreen,
"YellowGreen" | "yellow_green" | "yellowgreen" | "yellow green" => YellowGreen,
s => Twitch::Turbo(RGB::from_hex(s)),
}
}
}
impl From<RGB> for Twitch {
fn from(rgb: RGB) -> Self {
twitch_colors()
.iter()
.find(|(_, color)| *color == rgb)
.map(|&(c, _)| c)
.unwrap_or_else(|| Twitch::Turbo(rgb))
}
}
impl std::fmt::Display for Twitch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Twitch::*;
match self {
Blue => write!(f, "Blue"),
BlueViolet => write!(f, "BlueViolet"),
CadetBlue => write!(f, "CadetBlue"),
Chocolate => write!(f, "Chocolate"),
Coral => write!(f, "Coral"),
DodgerBlue => write!(f, "DodgerBlue"),
Firebrick => write!(f, "Firebrick"),
GoldenRod => write!(f, "GoldenRod"),
Green => write!(f, "Green"),
HotPink => write!(f, "HotPink"),
OrangeRed => write!(f, "OrangeRed"),
Red => write!(f, "Red"),
SeaGreen => write!(f, "SeaGreen"),
SpringGreen => write!(f, "SpringGreen"),
YellowGreen => write!(f, "YellowGreen"),
Turbo(rgb) => write!(f, "{}", rgb),
}
}
}
pub const fn twitch_colors() -> [(Twitch, RGB); 15] {
use Twitch::*;
[
(Blue, RGB(0x00, 0x00, 0xFF)),
(BlueViolet, RGB(0x8A, 0x2B, 0xE2)),
(CadetBlue, RGB(0x5F, 0x9E, 0xA0)),
(Chocolate, RGB(0xD2, 0x69, 0x1E)),
(Coral, RGB(0xFF, 0x7F, 0x50)),
(DodgerBlue, RGB(0x1E, 0x90, 0xFF)),
(Firebrick, RGB(0xB2, 0x22, 0x22)),
(GoldenRod, RGB(0xDA, 0xA5, 0x20)),
(Green, RGB(0x00, 0x80, 0x00)),
(HotPink, RGB(0xFF, 0x69, 0xB4)),
(OrangeRed, RGB(0xFF, 0x45, 0x00)),
(Red, RGB(0xFF, 0x00, 0x00)),
(SeaGreen, RGB(0x2E, 0x8B, 0x57)),
(SpringGreen, RGB(0x00, 0xFF, 0x7F)),
(YellowGreen, RGB(0xAD, 0xFF, 0x2F)),
]
}