1#[repr(u32)]
5#[derive(Clone, Copy, Debug, Default, PartialEq)]
6pub enum ColorName {
7 #[default]
9 Reserved,
10 Rgb(u32),
12 Variant(ColorVariant),
14}
15
16impl ColorName {
17 pub const fn new() -> ColorName {
19 ColorName::Reserved
20 }
21}
22
23#[repr(u32)]
25#[derive(Clone, Copy, Debug, Default, PartialEq)]
26pub enum ColorVariant {
27 #[default]
28 Black = 0x000000,
29}
30
31impl From<ColorName> for u32 {
32 fn from(val: ColorName) -> Self {
33 match val {
34 ColorName::Reserved => 0,
35 ColorName::Rgb(color) => color,
36 ColorName::Variant(color) => color as u32,
37 }
38 }
39}
40
41impl From<&str> for ColorName {
42 fn from(val: &str) -> Self {
43 if val.starts_with("rgb:") && val.len() >= 10 {
44 if let Ok(rgb) = u32::from_str_radix(&val[4..].to_lowercase()[..6], 16) {
45 Self::Rgb(rgb)
46 } else {
47 Self::Reserved
48 }
49 } else if val.starts_with('#') && val.len() >= 7 {
50 if let Ok(rgb) = u32::from_str_radix(&val[1..].to_lowercase()[..6], 16) {
51 Self::Rgb(rgb)
52 } else {
53 Self::Reserved
54 }
55 } else {
56 match val {
57 "black" => Self::Variant(ColorVariant::Black),
58 _ => Self::Reserved,
59 }
60 }
61 }
62}
63
64#[repr(C)]
66#[derive(Clone, Copy, Debug, Default, PartialEq)]
67pub struct Rgb {
68 r: u8,
69 g: u8,
70 b: u8,
71}
72
73impl Rgb {
74 pub const fn new() -> Self {
76 Self { r: 0, g: 0, b: 0 }
77 }
78
79 pub const fn create(r: u8, g: u8, b: u8) -> Self {
81 Self { r, g, b }
82 }
83
84 pub const fn r(&self) -> u8 {
86 self.r
87 }
88
89 pub fn set_r(&mut self, r: u8) {
91 self.r = r;
92 }
93
94 pub const fn g(&self) -> u8 {
96 self.g
97 }
98
99 pub fn set_g(&mut self, g: u8) {
101 self.g = g;
102 }
103
104 pub const fn b(&self) -> u8 {
106 self.b
107 }
108
109 pub fn set_b(&mut self, b: u8) {
111 self.b = b;
112 }
113}
114
115impl From<ColorName> for Rgb {
116 fn from(val: ColorName) -> Self {
117 let rgb = u32::from(val);
118
119 Self {
120 r: ((rgb & 0xff0000) >> 16) as u8,
121 g: ((rgb & 0xff00) >> 8) as u8,
122 b: (rgb & 0xff) as u8,
123 }
124 }
125}
126
127#[repr(C)]
129#[derive(Clone, Copy, Debug, Default, PartialEq)]
130pub struct Color {
131 pub name: ColorName,
132 pub rgb: Rgb,
133}
134
135impl Color {
136 pub const fn new() -> Self {
138 Self {
139 name: ColorName::new(),
140 rgb: Rgb::new(),
141 }
142 }
143}
144
145impl From<&str> for Color {
146 fn from(val: &str) -> Self {
147 let name = ColorName::from(val);
148 let rgb = Rgb::from(name);
149
150 Self { name, rgb }
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157 use crate::Result;
158
159 #[test]
160 fn test_color_parsing() -> Result<()> {
161 let color_str = "black";
162 let rgb0_str = "rgb:AB1122";
163 let rgb1_str = "#A1c022";
164 let invalid_str = "not a RGB color";
165 let too_short0_str = "rgb:1";
166 let too_short1_str = "#1";
167 let rgb_trailing_str = "#A1c022whatisallthistrailgarbage";
168
169 assert_eq!(
170 ColorName::from(color_str),
171 ColorName::Variant(ColorVariant::Black)
172 );
173 assert_eq!(ColorName::from(rgb0_str), ColorName::Rgb(0xab1122));
174 assert_eq!(ColorName::from(rgb1_str), ColorName::Rgb(0xa1c022));
175 assert_eq!(ColorName::from(invalid_str), ColorName::Reserved);
176 assert_eq!(ColorName::from(rgb_trailing_str), ColorName::Rgb(0xa1c022));
177 assert_eq!(ColorName::from(too_short0_str), ColorName::Reserved);
178 assert_eq!(ColorName::from(too_short1_str), ColorName::Reserved);
179
180 Ok(())
181 }
182}