1use crate::utils::{conversion, parser};
2
3#[derive(Debug, PartialEq, Clone)]
5pub struct Color {
6 pub(crate) rgba: (u8, u8, u8, f64),
7}
8
9impl Color {
10 pub fn new(r: u8, g: u8, b: u8, alpha: f64) -> Color {
11 Color {
12 rgba: (r, g, b, alpha),
13 }
14 }
15}
16
17impl From<&str> for Color {
18 fn from(str: &str) -> Self {
19 let low_str = str.to_lowercase();
20 let (r, g, b, a) = match &low_str {
21 str if str.starts_with("#") => conversion::hex::hex2rgb(str),
22 str if str.starts_with("rgba") => parser::parse_rgba_str(str),
23 str if str.starts_with("rgb") => parser::parse_rgb_str(str),
24 str if str.starts_with("lab") => {
25 let (l, a, b) = parser::parse_lab_str(str);
26 conversion::lab::lab2rgb((l, a, b))
27 }
28 str if str.starts_with("hsl") => {
29 let (h, s, l) = parser::parse_hsl_str(str);
30 let (r, g, b) = conversion::hsl::hsl2rgb((h, s, l));
31 (r, g, b, 1.0)
32 }
33 str if str.starts_with("hsv") => {
34 let (h, s, v) = parser::parse_hsv_str(str);
35 let (r, g, b) = conversion::hsv::hsv2rgb((h, s, v));
36 (r, g, b, 1.0)
37 }
38 str if str.starts_with("cmyk") => {
39 let (c, m, y, k) = parser::parse_cmyk_str(str);
40 let (r, g, b) = conversion::cmyk::cmyk2rgb((c, m, y, k));
41 (r, g, b, 1.0)
42 }
43 _ => {
44 let found = crate::W3CX11.get(str);
45 match found {
46 Some(hex) => conversion::hex::hex2rgb(hex),
47 None => panic!("Color not found"),
48 }
49 }
50 };
51 Color::new(r, g, b, a)
52 }
53}
54
55impl From<u32> for Color {
56 fn from(num: u32) -> Self {
57 let (r, g, b) = conversion::num::num2rgb(num);
58 Color {
59 rgba: (r, g, b, 1.0),
60 }
61 }
62}
63
64impl Iterator for Color {
65 type Item = f64;
66
67 fn next(&mut self) -> Option<Self::Item> {
68 let (r, g, b, a) = self.rgba();
69 vec![r as f64, g as f64, b as f64, a].into_iter().next()
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_color_from_hex_str() {
79 let hex_color = Color::from("#ff0000");
80 assert_eq!(hex_color.rgba, (255, 0, 0, 1.0));
81
82 let hex_color = Color::from("#abcdef");
83 assert_eq!(hex_color.hex(), "#abcdef");
84 }
85
86 #[test]
87 fn test_color_from_rgb_str() {
88 let rgb_color = Color::from("rgb(255, 255, 255)");
89 assert_eq!(
90 rgb_color,
91 Color {
92 rgba: (255, 255, 255, 1.)
93 }
94 );
95
96 let rgba_color = Color::from("rgba(255, 255, 255, 0.6)");
97 assert_eq!(
98 rgba_color,
99 Color {
100 rgba: (255, 255, 255, 0.6)
101 }
102 );
103 }
104
105 #[test]
106 fn test_color_from_lab_str() {
107 let lab_color = Color::from("lab(100, 0, 0)");
108 assert_eq!(
109 lab_color,
110 Color {
111 rgba: (255, 255, 255, 1.)
112 }
113 );
114 }
115
116 #[test]
117 fn test_color_from_name_str() {
118 let name_color = Color::from("mediumspringgreen");
119 assert_eq!(
120 name_color,
121 Color {
122 rgba: (0, 250, 154, 1.)
123 }
124 );
125 }
126
127 #[test]
128 fn test_color_from_hsl_str() {
129 let hsl_color = Color::from("hsl(0, 100%, 50%)");
130 assert_eq!(
131 hsl_color,
132 Color {
133 rgba: (255, 0, 0, 1.)
134 }
135 );
136
137 let hsl_color = Color::from("hsl(120, 100%, 50%)");
138 assert_eq!(
139 hsl_color,
140 Color {
141 rgba: (0, 255, 0, 1.)
142 }
143 );
144
145 let hsl_color = Color::from("hsl(240, 100%, 50%)");
146 assert_eq!(
147 hsl_color,
148 Color {
149 rgba: (0, 0, 255, 1.)
150 }
151 );
152 }
153
154 #[test]
155 fn test_color_from_hsv_str() {
156 let hsv_color = Color::from("hsv(0°,0%,75%)");
157 assert_eq!(
158 hsv_color,
159 Color {
160 rgba: (191, 191, 191, 1.)
161 }
162 );
163
164 let hsv_color = Color::from("hsv(120, 100%, 100%)");
165 assert_eq!(
166 hsv_color,
167 Color {
168 rgba: (0, 255, 0, 1.)
169 }
170 );
171
172 let hsv_color = Color::from("hsv(240, 100%, 100%)");
173 assert_eq!(
174 hsv_color,
175 Color {
176 rgba: (0, 0, 255, 1.)
177 }
178 );
179 }
180
181 #[test]
182 fn test_color_from_num() {
183 let num_color = Color::from(0xff0000);
184 assert_eq!(
185 num_color,
186 Color {
187 rgba: (255, 0, 0, 1.)
188 }
189 );
190
191 let num_color = Color::from(0xffff00);
192 assert_eq!(
193 num_color,
194 Color {
195 rgba: (255, 255, 0, 1.)
196 }
197 );
198
199 let num_color = Color::from(0x00ff00);
200 assert_eq!(
201 num_color,
202 Color {
203 rgba: (0, 255, 0, 1.)
204 }
205 );
206
207 let num_color = Color::from(11259375);
208 assert_eq!(num_color.hex(), "#abcdef");
209 }
210
211 #[test]
212 fn test_color_from_cmyk_str() {
213 let cmyk_color = Color::from("cmyk(0, 100%, 100%, 0)");
214 assert_eq!(cmyk_color.hex(), "#ff0000");
215
216 let cmyk_color = Color::from("cmyk(100%, 0, 100%, 0)");
217 assert_eq!(cmyk_color.hex(), "#00ff00");
218
219 let cmyk_color = Color::from("cmyk(100%, 100%, 0, 0)");
220 assert_eq!(cmyk_color.hex(), "#0000ff");
221
222 let cmyk_color = Color::from("cmyk(0, 0, 0, 100%)");
223 assert_eq!(cmyk_color.hex(), "#000000");
224
225 let cmyk_color = Color::from("cmyk(0, 0, 0, 0)");
226 assert_eq!(cmyk_color.hex(), "#ffffff");
227
228 let cmyk_color = Color::from("cmyk(20%, 80%, 0, 0)");
229 assert_eq!(cmyk_color.hex(), "#cc33ff");
230
231 let cmyk_color = Color::from("cmyk(35%, 0, 60%, 0)");
232 assert_eq!(cmyk_color.hex(), "#a6ff66");
233 }
234}