1use std::fmt;
5
6use rgb::Rgb;
7use strum::EnumCount;
8use tinyrand::{RandRange, StdRand};
9
10use super::ExtendedColour;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount)]
14#[allow(missing_docs)]
15pub enum Purple {
16 Indigo,
17 Purple,
18 DarkMagenta,
19 DarkViolet,
20 DarkSlateBlue,
21 BlueViolet,
22 DarkOrchid,
23 Fuchsia,
24 Magenta,
25 SlateBlue,
26 MediumSlateBlue,
27 MediumOrchid,
28 MediumPurple,
29 Orchid,
30 Violet,
31 Plum,
32 Thistle,
33 Lavender,
34 Pink,
35 MediumVioletRed,
36 PaleVioletRed,
37 DeepPink,
38 HotPink,
39 LightPink,
40}
41
42impl fmt::Display for Purple {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 Self::Indigo => write!(f, "#4B0082"),
46 Self::Purple => write!(f, "#800080"),
47 Self::DarkMagenta => write!(f, "#8B008B"),
48 Self::DarkViolet => write!(f, "#9400D3"),
49 Self::DarkSlateBlue => write!(f, "#483D8B"),
50 Self::BlueViolet => write!(f, "#8A2BE2"),
51 Self::DarkOrchid => write!(f, "#9932CC"),
52 Self::Fuchsia => write!(f, "#FF00FF"),
53 Self::Magenta => write!(f, "#FF00FF"),
54 Self::SlateBlue => write!(f, "#6A5ACD"),
55 Self::MediumSlateBlue => write!(f, "#7B68EE"),
56 Self::MediumOrchid => write!(f, "#BA55D3"),
57 Self::MediumPurple => write!(f, "#9370DB"),
58 Self::Orchid => write!(f, "#DA70D6"),
59 Self::Violet => write!(f, "#EE82EE"),
60 Self::Plum => write!(f, "#DDA0DD"),
61 Self::Thistle => write!(f, "#D8BFD8"),
62 Self::Lavender => write!(f, "#E6E6FA"),
63 Self::Pink => write!(f, "#FFC0CB"),
64 Self::MediumVioletRed => write!(f, "#C71585"),
65 Self::PaleVioletRed => write!(f, "#DB7093"),
66 Self::DeepPink => write!(f, "#FF1493"),
67 Self::HotPink => write!(f, "#FF69B4"),
68 Self::LightPink => write!(f, "#FFB6C1"),
69 }
70 }
71}
72
73impl_colour_methods!(Purple);
74
75impl Purple {
76 pub fn parse(name: &str) -> Option<Self> {
91 match name.to_lowercase().as_str() {
92 "#4b0082" | "4b0082" | "indigo" => Some(Self::Indigo),
93 "#800080" | "800080" | "purple" => Some(Self::Purple),
94 "#8b008b" | "8b008b" | "darkmagenta" => Some(Self::DarkMagenta),
95 "#9400d3" | "9400d3" | "darkviolet" => Some(Self::DarkViolet),
96 "#483d8b" | "483d8b" | "darkslateblue" => Some(Self::DarkSlateBlue),
97 "#8a2be2" | "8a2be2" | "blueviolet" => Some(Self::BlueViolet),
98 "#9932cc" | "9932cc" | "darkorchid" => Some(Self::DarkOrchid),
99 "#a020f0" | "a020f0" | "fuchsia" => Some(Self::Fuchsia),
100 "#ff00ff" | "ff00ff" | "magenta" => Some(Self::Magenta),
101 "#6a5acd" | "6a5acd" | "slateblue" => Some(Self::SlateBlue),
102 "#7b68ee" | "7b68ee" | "mediumslateblue" => Some(Self::MediumSlateBlue),
103 "#ba55d3" | "ba55d3" | "mediumorchid" => Some(Self::MediumOrchid),
104 "#9370db" | "9370db" | "mediumpurple" => Some(Self::MediumPurple),
105 "#da70d6" | "da70d6" | "orchid" => Some(Self::Orchid),
106 "#ee82ee" | "ee82ee" | "violet" => Some(Self::Violet),
107 "#dda0dd" | "dda0dd" | "plum" => Some(Self::Plum),
108 "#d8bfd8" | "d8bfd8" | "thistle" => Some(Self::Thistle),
109 "#e6e6fa" | "e6e6fa" | "lavender" => Some(Self::Lavender),
110 "#ffc0cb" | "ffc0cb" | "pink" => Some(Self::Pink),
111 "#c71585" | "c71585" | "mediumvioletred" => Some(Self::MediumVioletRed),
112 "#db7093" | "db7093" | "palevioletred" => Some(Self::PaleVioletRed),
113 "#ff1493" | "ff1493" | "deeppink" => Some(Self::DeepPink),
114 "#ff69b4" | "ff69b4" | "hotpink" => Some(Self::HotPink),
115 "#ffb6c1" | "ffb6c1" | "lightpink" => Some(Self::LightPink),
116 _ => None,
117 }
118 }
119
120 pub fn random() -> Self {
132 let mut rand = StdRand::default();
133
134 match rand.next_range(0..Self::COUNT) {
135 0 => Self::Indigo,
136 1 => Self::Purple,
137 2 => Self::DarkMagenta,
138 3 => Self::DarkViolet,
139 4 => Self::DarkSlateBlue,
140 5 => Self::BlueViolet,
141 6 => Self::DarkOrchid,
142 7 => Self::Fuchsia,
143 8 => Self::Magenta,
144 9 => Self::SlateBlue,
145 10 => Self::MediumSlateBlue,
146 11 => Self::MediumOrchid,
147 12 => Self::MediumPurple,
148 13 => Self::Orchid,
149 14 => Self::Violet,
150 15 => Self::Plum,
151 16 => Self::Thistle,
152 17 => Self::Lavender,
153 18 => Self::Pink,
154 19 => Self::MediumVioletRed,
155 20 => Self::PaleVioletRed,
156 21 => Self::DeepPink,
157 22 => Self::HotPink,
158 23 => Self::LightPink,
159 _ => Self::Purple,
160 }
161 }
162}
163
164impl ExtendedColour for Purple {}
165
166#[cfg(test)]
167mod tests {
168 use std::str::FromStr;
169
170 use crate::Prefix;
171
172 use super::*;
173 use rstest::rstest;
174
175 #[rstest]
176 #[case(Purple::Purple, "rgb(128,0,128)")]
177 #[case(Purple::Thistle, "rgb(216,191,216)")]
178 #[case(Purple::Plum, "rgb(221,160,221)")]
179 #[case(Purple::Violet, "rgb(238,130,238)")]
180 #[case(Purple::Magenta, "rgb(255,0,255)")]
181 #[case(Purple::Fuchsia, "rgb(255,0,255)")]
182 #[case(Purple::Orchid, "rgb(218,112,214)")]
183 #[case(Purple::MediumVioletRed, "rgb(199,21,133)")]
184 #[case(Purple::PaleVioletRed, "rgb(219,112,147)")]
185 #[case(Purple::DeepPink, "rgb(255,20,147)")]
186 #[case(Purple::HotPink, "rgb(255,105,180)")]
187 #[case(Purple::LightPink, "rgb(255,182,193)")]
188 #[case(Purple::Pink, "rgb(255,192,203)")]
189 fn test_rgb_string(#[case] colour: Purple, #[case] expected: String) {
190 let rgb_colour = colour.to_rgb();
191 let string = rgb_colour.to_string();
192
193 assert_eq!(expected, string);
194 }
195
196 #[rstest]
197 #[case(Purple::Purple, "800080")]
198 #[case(Purple::Thistle, "D8BFD8")]
199 #[case(Purple::Plum, "DDA0DD")]
200 #[case(Purple::Violet, "EE82EE")]
201 #[case(Purple::Magenta, "FF00FF")]
202 #[case(Purple::Fuchsia, "FF00FF")]
203 #[case(Purple::Orchid, "DA70D6")]
204 #[case(Purple::MediumVioletRed, "C71585")]
205 #[case(Purple::PaleVioletRed, "DB7093")]
206 #[case(Purple::DeepPink, "FF1493")]
207 #[case(Purple::HotPink, "FF69B4")]
208 #[case(Purple::LightPink, "FFB6C1")]
209 #[case(Purple::Pink, "FFC0CB")]
210 fn test_hex_triplet_string(
211 #[case] colour: Purple,
212 #[values(Prefix::None, Prefix::Hash)] prefix: Prefix,
213 #[case] expected: String,
214 ) {
215 let prefix_string = match prefix {
216 Prefix::None => "".to_string(),
217 Prefix::Hash => "#".to_string(),
218 };
219
220 let expected = format!("{prefix_string}{expected}");
221
222 let hex_colour = colour.to_hex_triplet(prefix);
223
224 assert_eq!(expected, hex_colour);
225 }
226
227 #[rstest]
228 #[case("#4b0082", Purple::Indigo)]
229 #[case("4b0082", Purple::Indigo)]
230 #[case("indigo", Purple::Indigo)]
231 #[case("#800080", Purple::Purple)]
232 #[case("800080", Purple::Purple)]
233 #[case("purple", Purple::Purple)]
234 #[case("#8b008b", Purple::DarkMagenta)]
235 #[case("8b008b", Purple::DarkMagenta)]
236 #[case("darkmagenta", Purple::DarkMagenta)]
237 #[case("#9400d3", Purple::DarkViolet)]
238 #[case("9400d3", Purple::DarkViolet)]
239 #[case("darkviolet", Purple::DarkViolet)]
240 #[case("#483d8b", Purple::DarkSlateBlue)]
241 #[case("483d8b", Purple::DarkSlateBlue)]
242 #[case("darkslateblue", Purple::DarkSlateBlue)]
243 #[case("#8a2be2", Purple::BlueViolet)]
244 #[case("8a2be2", Purple::BlueViolet)]
245 #[case("blueviolet", Purple::BlueViolet)]
246 #[case("#9932cc", Purple::DarkOrchid)]
247 #[case("9932cc", Purple::DarkOrchid)]
248 #[case("darkorchid", Purple::DarkOrchid)]
249 #[case("#a020f0", Purple::Fuchsia)]
250 #[case("a020f0", Purple::Fuchsia)]
251 #[case("fuchsia", Purple::Fuchsia)]
252 #[case("#ff00ff", Purple::Magenta)]
253 #[case("ff00ff", Purple::Magenta)]
254 #[case("magenta", Purple::Magenta)]
255 #[case("#6a5acd", Purple::SlateBlue)]
256 #[case("6a5acd", Purple::SlateBlue)]
257 #[case("slateblue", Purple::SlateBlue)]
258 #[case("#7b68ee", Purple::MediumSlateBlue)]
259 #[case("7b68ee", Purple::MediumSlateBlue)]
260 #[case("mediumslateblue", Purple::MediumSlateBlue)]
261 #[case("#ba55d3", Purple::MediumOrchid)]
262 #[case("ba55d3", Purple::MediumOrchid)]
263 #[case("mediumorchid", Purple::MediumOrchid)]
264 #[case("#9370db", Purple::MediumPurple)]
265 #[case("9370db", Purple::MediumPurple)]
266 #[case("mediumpurple", Purple::MediumPurple)]
267 #[case("#da70d6", Purple::Orchid)]
268 #[case("da70d6", Purple::Orchid)]
269 #[case("orchid", Purple::Orchid)]
270 #[case("#ee82ee", Purple::Violet)]
271 #[case("ee82ee", Purple::Violet)]
272 #[case("violet", Purple::Violet)]
273 #[case("#dda0dd", Purple::Plum)]
274 #[case("dda0dd", Purple::Plum)]
275 #[case("plum", Purple::Plum)]
276 #[case("#d8bfd8", Purple::Thistle)]
277 #[case("d8bfd8", Purple::Thistle)]
278 #[case("thistle", Purple::Thistle)]
279 #[case("#e6e6fa", Purple::Lavender)]
280 #[case("e6e6fa", Purple::Lavender)]
281 #[case("lavender", Purple::Lavender)]
282 #[case("#ffc0cb", Purple::Pink)]
283 #[case("ffc0cb", Purple::Pink)]
284 #[case("pink", Purple::Pink)]
285 #[case("#c71585", Purple::MediumVioletRed)]
286 #[case("c71585", Purple::MediumVioletRed)]
287 #[case("mediumvioletred", Purple::MediumVioletRed)]
288 #[case("#db7093", Purple::PaleVioletRed)]
289 #[case("db7093", Purple::PaleVioletRed)]
290 #[case("palevioletred", Purple::PaleVioletRed)]
291 #[case("deeppink", Purple::DeepPink)]
292 #[case("ff1493", Purple::DeepPink)]
293 #[case("deeppink", Purple::DeepPink)]
294 #[case("#ff69b4", Purple::HotPink)]
295 #[case("ff69b4", Purple::HotPink)]
296 #[case("hotpink", Purple::HotPink)]
297 #[case("#ffb6c1", Purple::LightPink)]
298 #[case("ffb6c1", Purple::LightPink)]
299 #[case("lightpink", Purple::LightPink)]
300 fn test_from_str(#[case] input: &str, #[case] expected: Purple) {
301 assert_eq!(expected, Purple::from_str(input).unwrap())
302 }
303
304 #[rstest]
305 #[case("#4b0082", Some(Purple::Indigo))]
306 #[case("4b0082", Some(Purple::Indigo))]
307 #[case("indigo", Some(Purple::Indigo))]
308 #[case("#800080", Some(Purple::Purple))]
309 #[case("800080", Some(Purple::Purple))]
310 #[case("purple", Some(Purple::Purple))]
311 #[case("#8b008b", Some(Purple::DarkMagenta))]
312 #[case("8b008b", Some(Purple::DarkMagenta))]
313 #[case("darkmagenta", Some(Purple::DarkMagenta))]
314 #[case("#9400d3", Some(Purple::DarkViolet))]
315 #[case("9400d3", Some(Purple::DarkViolet))]
316 #[case("darkviolet", Some(Purple::DarkViolet))]
317 #[case("#483d8b", Some(Purple::DarkSlateBlue))]
318 #[case("483d8b", Some(Purple::DarkSlateBlue))]
319 #[case("darkslateblue", Some(Purple::DarkSlateBlue))]
320 #[case("#8a2be2", Some(Purple::BlueViolet))]
321 #[case("8a2be2", Some(Purple::BlueViolet))]
322 #[case("blueviolet", Some(Purple::BlueViolet))]
323 #[case("#9932cc", Some(Purple::DarkOrchid))]
324 #[case("9932cc", Some(Purple::DarkOrchid))]
325 #[case("darkorchid", Some(Purple::DarkOrchid))]
326 #[case("#a020f0", Some(Purple::Fuchsia))]
327 #[case("a020f0", Some(Purple::Fuchsia))]
328 #[case("fuchsia", Some(Purple::Fuchsia))]
329 #[case("#ff00ff", Some(Purple::Magenta))]
330 #[case("ff00ff", Some(Purple::Magenta))]
331 #[case("magenta", Some(Purple::Magenta))]
332 #[case("#6a5acd", Some(Purple::SlateBlue))]
333 #[case("6a5acd", Some(Purple::SlateBlue))]
334 #[case("slateblue", Some(Purple::SlateBlue))]
335 #[case("#7b68ee", Some(Purple::MediumSlateBlue))]
336 #[case("7b68ee", Some(Purple::MediumSlateBlue))]
337 #[case("mediumslateblue", Some(Purple::MediumSlateBlue))]
338 #[case("#ba55d3", Some(Purple::MediumOrchid))]
339 #[case("ba55d3", Some(Purple::MediumOrchid))]
340 #[case("mediumorchid", Some(Purple::MediumOrchid))]
341 #[case("#9370db", Some(Purple::MediumPurple))]
342 #[case("9370db", Some(Purple::MediumPurple))]
343 #[case("mediumpurple", Some(Purple::MediumPurple))]
344 #[case("#da70d6", Some(Purple::Orchid))]
345 #[case("da70d6", Some(Purple::Orchid))]
346 #[case("orchid", Some(Purple::Orchid))]
347 #[case("#ee82ee", Some(Purple::Violet))]
348 #[case("ee82ee", Some(Purple::Violet))]
349 #[case("violet", Some(Purple::Violet))]
350 #[case("#dda0dd", Some(Purple::Plum))]
351 #[case("dda0dd", Some(Purple::Plum))]
352 #[case("plum", Some(Purple::Plum))]
353 #[case("#d8bfd8", Some(Purple::Thistle))]
354 #[case("d8bfd8", Some(Purple::Thistle))]
355 #[case("thistle", Some(Purple::Thistle))]
356 #[case("#e6e6fa", Some(Purple::Lavender))]
357 #[case("e6e6fa", Some(Purple::Lavender))]
358 #[case("lavender", Some(Purple::Lavender))]
359 #[case("#ffc0cb", Some(Purple::Pink))]
360 #[case("ffc0cb", Some(Purple::Pink))]
361 #[case("pink", Some(Purple::Pink))]
362 #[case("#c71585", Some(Purple::MediumVioletRed))]
363 #[case("c71585", Some(Purple::MediumVioletRed))]
364 #[case("mediumvioletred", Some(Purple::MediumVioletRed))]
365 #[case("#db7093", Some(Purple::PaleVioletRed))]
366 #[case("db7093", Some(Purple::PaleVioletRed))]
367 #[case("palevioletred", Some(Purple::PaleVioletRed))]
368 #[case("deeppink", Some(Purple::DeepPink))]
369 #[case("ff1493", Some(Purple::DeepPink))]
370 #[case("deeppink", Some(Purple::DeepPink))]
371 #[case("#ff69b4", Some(Purple::HotPink))]
372 #[case("ff69b4", Some(Purple::HotPink))]
373 #[case("hotpink", Some(Purple::HotPink))]
374 #[case("#ffb6c1", Some(Purple::LightPink))]
375 #[case("ffb6c1", Some(Purple::LightPink))]
376 #[case("lightpink", Some(Purple::LightPink))]
377 #[case("012345", None)]
378 fn test_name_colour(#[case] input: &str, #[case] expected: Option<Purple>) {
379 assert_eq!(expected, Purple::name_colour(input))
380 }
381}