named_colour/ext/
purple.rs

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