named_colour/ext/
white.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 white
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount)]
16#[allow(missing_docs)]
17pub enum White {
18    AntiqueWhite,
19    Beige,
20    Bisque,
21    BlanchedAlmond,
22    Wheat,
23    CornSilk,
24    White,
25    NavajoWhite,
26    MistyRose,
27    LavenderBlush,
28    Linen,
29    OldLace,
30    SeaShell,
31    MintCream,
32    FloralWhite,
33    GhostWhite,
34    Ivory,
35    Snow,
36    WhiteSmoke,
37    AliceBlue,
38}
39
40impl fmt::Display for White {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::AntiqueWhite => write!(f, "#FAEBD7"),
44            Self::Beige => write!(f, "#F5F5DC"),
45            Self::Bisque => write!(f, "#FFE4C4"),
46            Self::BlanchedAlmond => write!(f, "#FFEBCD"),
47            Self::Wheat => write!(f, "#F5DEB3"),
48            Self::CornSilk => write!(f, "#FFF8DC"),
49            Self::White => write!(f, "#FFFFFF"),
50            Self::NavajoWhite => write!(f, "#FFDEAD"),
51            Self::MistyRose => write!(f, "#FFE4E1"),
52            Self::LavenderBlush => write!(f, "#FFF0F5"),
53            Self::Linen => write!(f, "#FAF0E6"),
54            Self::OldLace => write!(f, "#FDF5E6"),
55            Self::SeaShell => write!(f, "#FFF5EE"),
56            Self::MintCream => write!(f, "#F5FFFA"),
57            Self::FloralWhite => write!(f, "#FFFAF0"),
58            Self::GhostWhite => write!(f, "#F8F8FF"),
59            Self::Ivory => write!(f, "#FFFFF0"),
60            Self::Snow => write!(f, "#FFFAFA"),
61            Self::WhiteSmoke => write!(f, "#F5F5F5"),
62            Self::AliceBlue => write!(f, "#F0F8FF"),
63        }
64    }
65}
66
67impl White {
68    /// Display the colour name as an RGB Tuple
69    ///
70    /// ## Example
71    ///
72    ///```
73    /// # use named_colour::ext::White;
74    /// # fn main() {
75    ///    let colour = White::OldLace;
76    ///    let rgb_colour = colour.to_rgb();
77    ///
78    ///    let string = rgb_colour.to_string();
79    ///    assert_eq!("rgb(253,245,230)", string);
80    ///
81    ///  # }
82    ///```
83    pub fn to_rgb(&self) -> Rgb<u8> {
84        let colour = self.to_string();
85
86        let r: u8 = u8::from_str_radix(&colour[1..3], 16).unwrap();
87        let g: u8 = u8::from_str_radix(&colour[3..5], 16).unwrap();
88        let b: u8 = u8::from_str_radix(&colour[5..7], 16).unwrap();
89
90        Rgb::new(r, g, b)
91    }
92
93    /// Display the colour name as an RGB Tuple
94    ///
95    /// ## Example
96    ///
97    ///```
98    /// # use named_colour::ext::White;
99    /// # use named_colour::Prefix;
100    ///    let colour = White::LavenderBlush;
101    ///
102    ///     assert_eq!("#FFF0F5", colour.to_hex_triplet(Prefix::Hash));
103    ///
104    ///```
105    pub fn to_hex_triplet(&self, prefix: Prefix) -> String {
106        let rgb = self.to_rgb();
107
108        let prefix = match prefix {
109            Prefix::Hash => "#",
110            Prefix::None => "",
111        };
112
113        format!("{}{:02X}{:02X}{:02X}", prefix, rgb.r, rgb.g, rgb.b)
114    }
115
116    /// Parse a colour from string
117    ///
118    /// ## Example
119    ///
120    ///```
121    /// # use named_colour::ext::White;
122    /// # fn main() {
123    ///    let colour = White::parse("AntiqueWhite");
124    ///    assert_eq!(Some(White::AntiqueWhite), colour);
125    ///
126    ///  # }
127    ///```
128    pub fn parse(name: &str) -> Option<Self> {
129        match name.to_lowercase().as_str() {
130            "#faebd7" | "faebd7" | "antiquewhite" => Some(Self::AntiqueWhite),
131            "#f5f5dc" | "f5f5dc" | "beige" => Some(Self::Beige),
132            "#ffe4c4" | "ffe4c4" | "bisque" => Some(Self::Bisque),
133            "#ffebcd" | "ffebcd" | "blanchedalmond" => Some(Self::BlanchedAlmond),
134            "#f5deb3" | "f5deb3" | "wheat" => Some(Self::Wheat),
135            "#fff8dc" | "fff8dc" | "cornsilk" => Some(Self::CornSilk),
136            "#ffffff" | "ffffff" | "white" => Some(Self::White),
137            "#ffdead" | "ffdead" | "navajowhite" => Some(Self::NavajoWhite),
138            "#ffe4e1" | "ffe4e1" | "mistyrose" => Some(Self::MistyRose),
139            "#fff0f5" | "fff0f5" | "lavenderblush" => Some(Self::LavenderBlush),
140            "#faf0e6" | "faf0e6" | "linen" => Some(Self::Linen),
141            "#fdf5e6" | "fdf5e6" | "oldlace" => Some(Self::OldLace),
142            "#fff5ee" | "fff5ee" | "seashell" => Some(Self::SeaShell),
143            "#f5fffa" | "f5fffa" | "mintcream" => Some(Self::MintCream),
144            "#fffaf0" | "fffaf0" | "floralwhite" => Some(Self::FloralWhite),
145            "#f8f8ff" | "f8f8ff" | "ghostwhite" => Some(Self::GhostWhite),
146            "#fffff0" | "fffff0" | "ivory" => Some(Self::Ivory),
147            "#fffafa" | "fffafa" | "snow" => Some(Self::Snow),
148            "#f5f5f5" | "f5f5f5" | "whitesmoke" => Some(Self::WhiteSmoke),
149            "#f0f8ff" | "f0f8ff" | "aliceblue" => Some(Self::AliceBlue),
150            _ => None,
151        }
152    }
153
154    /// Generate a random colour
155    ///     
156    /// ## Example
157    ///
158    ///```
159    /// # use named_colour::ext::White;
160    /// # fn main() {
161    ///    let colour = White::random();
162    ///
163    /// # }
164    /// ```
165    pub fn random() -> Self {
166        let mut rand = StdRand::default();
167
168        match rand.next_range(0..Self::COUNT) {
169            0 => Self::AntiqueWhite,
170            1 => Self::Beige,
171            2 => Self::Bisque,
172            3 => Self::BlanchedAlmond,
173            4 => Self::Wheat,
174            5 => Self::CornSilk,
175            6 => Self::White,
176            7 => Self::NavajoWhite,
177            8 => Self::MistyRose,
178            9 => Self::LavenderBlush,
179            10 => Self::Linen,
180            11 => Self::OldLace,
181            12 => Self::SeaShell,
182            13 => Self::MintCream,
183            14 => Self::FloralWhite,
184            15 => Self::GhostWhite,
185            16 => Self::Ivory,
186            17 => Self::Snow,
187            18 => Self::WhiteSmoke,
188            19 => Self::AliceBlue,
189            _ => Self::White,
190        }
191    }
192}
193
194impl FromStr for White {
195    type Err = String;
196    fn from_str(s: &str) -> Result<Self, Self::Err> {
197        match Self::parse(s) {
198            Some(colour) => Ok(colour),
199            None => Err(format!("Invalid Colour: {s}")),
200        }
201    }
202}
203
204impl ExtendedColour for White {}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209    use rstest::rstest;
210
211    #[rstest]
212    #[case(White::AntiqueWhite, "rgb(250,235,215)")]
213    #[case(White::Beige, "rgb(245,245,220)")]
214    #[case(White::Bisque, "rgb(255,228,196)")]
215    #[case(White::BlanchedAlmond, "rgb(255,235,205)")]
216    #[case(White::Wheat, "rgb(245,222,179)")]
217    #[case(White::CornSilk, "rgb(255,248,220)")]
218    #[case(White::White, "rgb(255,255,255)")]
219    #[case(White::NavajoWhite, "rgb(255,222,173)")]
220    #[case(White::MistyRose, "rgb(255,228,225)")]
221    #[case(White::LavenderBlush, "rgb(255,240,245)")]
222    #[case(White::Linen, "rgb(250,240,230)")]
223    #[case(White::OldLace, "rgb(253,245,230)")]
224    #[case(White::SeaShell, "rgb(255,245,238)")]
225    #[case(White::MintCream, "rgb(245,255,250)")]
226    #[case(White::FloralWhite, "rgb(255,250,240)")]
227    #[case(White::GhostWhite, "rgb(248,248,255)")]
228    #[case(White::Ivory, "rgb(255,255,240)")]
229    #[case(White::Snow, "rgb(255,250,250)")]
230    #[case(White::WhiteSmoke, "rgb(245,245,245)")]
231    fn test_rgb_string(#[case] colour: White, #[case] expected: String) {
232        let rgb_colour = colour.to_rgb();
233        let string = rgb_colour.to_string();
234
235        assert_eq!(expected, string);
236    }
237
238    #[rstest]
239    #[case(White::AntiqueWhite, "FAEBD7")]
240    #[case(White::Beige, "F5F5DC")]
241    #[case(White::Bisque, "FFE4C4")]
242    #[case(White::BlanchedAlmond, "FFEBCD")]
243    #[case(White::Wheat, "F5DEB3")]
244    #[case(White::CornSilk, "FFF8DC")]
245    #[case(White::White, "FFFFFF")]
246    #[case(White::NavajoWhite, "FFDEAD")]
247    #[case(White::MistyRose, "FFE4E1")]
248    #[case(White::LavenderBlush, "FFF0F5")]
249    #[case(White::Linen, "FAF0E6")]
250    #[case(White::OldLace, "FDF5E6")]
251    #[case(White::SeaShell, "FFF5EE")]
252    #[case(White::MintCream, "F5FFFA")]
253    #[case(White::FloralWhite, "FFFAF0")]
254    #[case(White::GhostWhite, "F8F8FF")]
255    #[case(White::Ivory, "FFFFF0")]
256    #[case(White::Snow, "FFFAFA")]
257    #[case(White::WhiteSmoke, "F5F5F5")]
258    fn test_hex_triplet_string(
259        #[case] colour: White,
260        #[values(Prefix::None, Prefix::Hash)] prefix: Prefix,
261        #[case] expected: String,
262    ) {
263        let prefix_string = match prefix {
264            Prefix::None => "".to_string(),
265            Prefix::Hash => "#".to_string(),
266        };
267
268        let expected = format!("{prefix_string}{expected}");
269
270        let hex_colour = colour.to_hex_triplet(prefix);
271
272        assert_eq!(expected, hex_colour);
273    }
274
275    #[rstest]
276    #[case("#faebd7", White::AntiqueWhite)]
277    #[case("faebd7", White::AntiqueWhite)]
278    #[case("AntiqueWhite", White::AntiqueWhite)]
279    #[case("#f5f5dc", White::Beige)]
280    #[case("f5f5dc", White::Beige)]
281    #[case("Beige", White::Beige)]
282    #[case("#ffe4c4", White::Bisque)]
283    #[case("ffe4c4", White::Bisque)]
284    #[case("Bisque", White::Bisque)]
285    #[case("#ffebcd", White::BlanchedAlmond)]
286    #[case("ffebcd", White::BlanchedAlmond)]
287    #[case("BlanchedAlmond", White::BlanchedAlmond)]
288    #[case("#f5deb3", White::Wheat)]
289    #[case("f5deb3", White::Wheat)]
290    #[case("wheat", White::Wheat)]
291    #[case("#fff8dc", White::CornSilk)]
292    #[case("fff8dc", White::CornSilk)]
293    #[case("CornSilk", White::CornSilk)]
294    #[case("#ffffff", White::White)]
295    #[case("ffffff", White::White)]
296    #[case("White", White::White)]
297    #[case("#ffdead", White::NavajoWhite)]
298    #[case("ffdead", White::NavajoWhite)]
299    #[case("NavajoWhite", White::NavajoWhite)]
300    #[case("#ffe4e1", White::MistyRose)]
301    #[case("ffe4e1", White::MistyRose)]
302    #[case("MistyRose", White::MistyRose)]
303    #[case("#fff0f5", White::LavenderBlush)]
304    #[case("fff0f5", White::LavenderBlush)]
305    #[case("LavenderBlush", White::LavenderBlush)]
306    #[case("#faf0e6", White::Linen)]
307    #[case("faf0e6", White::Linen)]
308    #[case("Linen", White::Linen)]
309    #[case("#fdf5e6", White::OldLace)]
310    #[case("fdf5e6", White::OldLace)]
311    #[case("OldLace", White::OldLace)]
312    #[case("#fff5ee", White::SeaShell)]
313    #[case("fff5ee", White::SeaShell)]
314    #[case("SeaShell", White::SeaShell)]
315    #[case("#f5fffa", White::MintCream)]
316    #[case("f5fffa", White::MintCream)]
317    #[case("MintCream", White::MintCream)]
318    #[case("#fffaf0", White::FloralWhite)]
319    #[case("fffaf0", White::FloralWhite)]
320    #[case("FloralWhite", White::FloralWhite)]
321    #[case("#f8f8ff", White::GhostWhite)]
322    #[case("f8f8ff", White::GhostWhite)]
323    #[case("GhostWhite", White::GhostWhite)]
324    #[case("#fffff0", White::Ivory)]
325    #[case("fffff0", White::Ivory)]
326    #[case("Ivory", White::Ivory)]
327    #[case("#fffafa", White::Snow)]
328    #[case("fffafa", White::Snow)]
329    #[case("Snow", White::Snow)]
330    #[case("#f5f5f5", White::WhiteSmoke)]
331    #[case("f5f5f5", White::WhiteSmoke)]
332    #[case("WhiteSmoke", White::WhiteSmoke)]
333    #[case("#f0f8ff", White::AliceBlue)]
334    #[case("f0f8ff", White::AliceBlue)]
335    #[case("AliceBlue", White::AliceBlue)]
336    fn test_from_str(#[case] input: &str, #[case] expected: White) {
337        assert_eq!(expected, White::from_str(input).unwrap())
338    }
339
340    #[rstest]
341    #[case("#faebd7", Some(White::AntiqueWhite))]
342    #[case("faebd7", Some(White::AntiqueWhite))]
343    #[case("AntiqueWhite", Some(White::AntiqueWhite))]
344    #[case("#f5f5dc", Some(White::Beige))]
345    #[case("f5f5dc", Some(White::Beige))]
346    #[case("Beige", Some(White::Beige))]
347    #[case("#ffe4c4", Some(White::Bisque))]
348    #[case("ffe4c4", Some(White::Bisque))]
349    #[case("Bisque", Some(White::Bisque))]
350    #[case("#ffebcd", Some(White::BlanchedAlmond))]
351    #[case("ffebcd", Some(White::BlanchedAlmond))]
352    #[case("BlanchedAlmond", Some(White::BlanchedAlmond))]
353    #[case("#f5deb3", Some(White::Wheat))]
354    #[case("f5deb3", Some(White::Wheat))]
355    #[case("wheat", Some(White::Wheat))]
356    #[case("#fff8dc", Some(White::CornSilk))]
357    #[case("fff8dc", Some(White::CornSilk))]
358    #[case("CornSilk", Some(White::CornSilk))]
359    #[case("#ffffff", Some(White::White))]
360    #[case("ffffff", Some(White::White))]
361    #[case("White", Some(White::White))]
362    #[case("#ffdead", Some(White::NavajoWhite))]
363    #[case("ffdead", Some(White::NavajoWhite))]
364    #[case("NavajoWhite", Some(White::NavajoWhite))]
365    #[case("#ffe4e1", Some(White::MistyRose))]
366    #[case("ffe4e1", Some(White::MistyRose))]
367    #[case("MistyRose", Some(White::MistyRose))]
368    #[case("#fff0f5", Some(White::LavenderBlush))]
369    #[case("fff0f5", Some(White::LavenderBlush))]
370    #[case("LavenderBlush", Some(White::LavenderBlush))]
371    #[case("#faf0e6", Some(White::Linen))]
372    #[case("faf0e6", Some(White::Linen))]
373    #[case("Linen", Some(White::Linen))]
374    #[case("#fdf5e6", Some(White::OldLace))]
375    #[case("fdf5e6", Some(White::OldLace))]
376    #[case("OldLace", Some(White::OldLace))]
377    #[case("#fff5ee", Some(White::SeaShell))]
378    #[case("fff5ee", Some(White::SeaShell))]
379    #[case("SeaShell", Some(White::SeaShell))]
380    #[case("#f5fffa", Some(White::MintCream))]
381    #[case("f5fffa", Some(White::MintCream))]
382    #[case("MintCream", Some(White::MintCream))]
383    #[case("#fffaf0", Some(White::FloralWhite))]
384    #[case("fffaf0", Some(White::FloralWhite))]
385    #[case("FloralWhite", Some(White::FloralWhite))]
386    #[case("#f8f8ff", Some(White::GhostWhite))]
387    #[case("f8f8ff", Some(White::GhostWhite))]
388    #[case("GhostWhite", Some(White::GhostWhite))]
389    #[case("#fffff0", Some(White::Ivory))]
390    #[case("fffff0", Some(White::Ivory))]
391    #[case("Ivory", Some(White::Ivory))]
392    #[case("#fffafa", Some(White::Snow))]
393    #[case("fffafa", Some(White::Snow))]
394    #[case("Snow", Some(White::Snow))]
395    #[case("#f5f5f5", Some(White::WhiteSmoke))]
396    #[case("f5f5f5", Some(White::WhiteSmoke))]
397    #[case("WhiteSmoke", Some(White::WhiteSmoke))]
398    #[case("#f0f8ff", Some(White::AliceBlue))]
399    #[case("f0f8ff", Some(White::AliceBlue))]
400    #[case("AliceBlue", Some(White::AliceBlue))]
401    #[case("012345", None)]
402    fn test_name_colour(#[case] input: &str, #[case] expected: Option<White>) {
403        assert_eq!(expected, White::name_colour(input))
404    }
405}