named_colour/ext/
yellow.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 yellow
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount)]
16#[allow(missing_docs)]
17pub enum Yellow {
18    Gold,
19    DarkGoldenrod,
20    Goldenrod,
21    PaleGoldenrod,
22    DarkKhaki,
23    Khaki,
24    Yellow,
25    YellowGreen,
26    PeachPuff,
27    Moccasin,
28    PapayaWhip,
29    LightGoldenrodYellow,
30    LemonChiffon,
31    LightYellow,
32}
33
34impl fmt::Display for Yellow {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            Self::Gold => write!(f, "#FFD700"),
38            Self::DarkGoldenrod => write!(f, "#B8860B"),
39            Self::Goldenrod => write!(f, "#DAA520"),
40            Self::PaleGoldenrod => write!(f, "#EEE8AA"),
41            Self::PeachPuff => write!(f, "#FFDAB9"),
42            Self::Moccasin => write!(f, "#FFE4B5"),
43            Self::PapayaWhip => write!(f, "#FFEFD5"),
44            Self::DarkKhaki => write!(f, "#BDB76B"),
45            Self::LemonChiffon => write!(f, "#FFFACD"),
46            Self::LightGoldenrodYellow => write!(f, "#FAFAD2"),
47            Self::Khaki => write!(f, "#F0E68C"),
48            Self::Yellow => write!(f, "#FFFF00"),
49            Self::YellowGreen => write!(f, "#9ACD32"),
50            Self::LightYellow => write!(f, "#FFFFE0"),
51        }
52    }
53}
54
55impl Yellow {
56    /// Display the colour name as an RGB Tuple
57    ///
58    /// ## Example
59    ///
60    ///```
61    /// # use named_colour::ext::Yellow;
62    /// # fn main() {
63    ///    let rgb_colour = Yellow::Khaki.to_rgb();
64    ///
65    ///    let string = rgb_colour.to_string();
66    ///    assert_eq!("rgb(240,230,140)", string);
67    ///
68    ///  # }
69    ///```
70    pub fn to_rgb(&self) -> Rgb<u8> {
71        let colour = self.to_string();
72
73        let r: u8 = u8::from_str_radix(&colour[1..3], 16).unwrap();
74        let g: u8 = u8::from_str_radix(&colour[3..5], 16).unwrap();
75        let b: u8 = u8::from_str_radix(&colour[5..7], 16).unwrap();
76
77        Rgb::new(r, g, b)
78    }
79
80    /// Display the colour name as an RGB Tuple
81    ///
82    /// ## Example
83    ///
84    ///```
85    /// # use named_colour::ext::Yellow;
86    /// # use named_colour::Prefix;
87    ///     let colour = Yellow::Khaki;
88    ///
89    ///     assert_eq!("#F0E68C", colour.to_hex_triplet(Prefix::Hash));
90    ///
91    ///```
92    pub fn to_hex_triplet(&self, prefix: Prefix) -> String {
93        let rgb = self.to_rgb();
94
95        let prefix = match prefix {
96            Prefix::Hash => "#",
97            Prefix::None => "",
98        };
99
100        format!("{}{:02X}{:02X}{:02X}", prefix, rgb.r, rgb.g, rgb.b)
101    }
102
103    /// Parse a colour from string
104    ///     
105    /// ## Example
106    ///
107    ///```
108    /// # use named_colour::ext::Yellow;
109    /// # use named_colour::Prefix;
110    ///     let colour = Yellow::Khaki;
111    ///     assert_eq!(Some(colour), Yellow::parse("Khaki"));
112    ///
113    ///```
114    ///
115    pub fn parse(name: &str) -> Option<Self> {
116        match name.to_lowercase().as_str() {
117            "#ffd700" | "ffd700" | "gold" => Some(Self::Gold),
118            "#b8860b" | "b8860b" | "darkgoldenrod" => Some(Self::DarkGoldenrod),
119            "#dab500" | "dab500" | "goldenrod" => Some(Self::Goldenrod),
120            "#eee8aa" | "eee8aa" | "palegoldenrod" => Some(Self::PaleGoldenrod),
121            "#bdb76b" | "bdb76b" | "darkkhaki" => Some(Self::DarkKhaki),
122            "#f0e68c" | "f0e68c" | "khaki" => Some(Self::Khaki),
123            "#ffff00" | "ffff00" | "yellow" => Some(Self::Yellow),
124            "#9acd32" | "9acd32" | "yellowgreen" => Some(Self::YellowGreen),
125            "#ffdab9" | "ffdab9" | "peachpuff" => Some(Self::PeachPuff),
126            "#ffe4b5" | "ffe4b5" | "moccasin" => Some(Self::Moccasin),
127            "#ffefd5" | "ffefd5" | "papayawhip" => Some(Self::PapayaWhip),
128            "#fffacd" | "fffacd" | "lemonchiffon" => Some(Self::LemonChiffon),
129            "#fafad2" | "fafad2" | "lightgoldenrodyellow" => Some(Self::LightGoldenrodYellow),
130            "#ffffe0" | "ffffe0" | "lightyellow" => Some(Self::LightYellow),
131            _ => None,
132        }
133    }
134
135    /// Generate a random colour
136    ///     
137    /// ## Example
138    ///
139    ///```
140    /// # use named_colour::ext::Yellow;
141    /// # fn main() {
142    ///    let colour = Yellow::random();
143    ///
144    /// # }
145    /// ```
146    pub fn random() -> Self {
147        let mut rand = StdRand::default();
148
149        match rand.next_range(0..Self::COUNT) {
150            0 => Self::Gold,
151            1 => Self::DarkGoldenrod,
152            2 => Self::Goldenrod,
153            3 => Self::PaleGoldenrod,
154            4 => Self::PeachPuff,
155            5 => Self::Moccasin,
156            6 => Self::PapayaWhip,
157            7 => Self::DarkKhaki,
158            8 => Self::LemonChiffon,
159            9 => Self::LightGoldenrodYellow,
160            10 => Self::Khaki,
161            11 => Self::Yellow,
162            12 => Self::YellowGreen,
163            13 => Self::LightYellow,
164            _ => Self::Yellow,
165        }
166    }
167}
168
169impl FromStr for Yellow {
170    type Err = String;
171    fn from_str(s: &str) -> Result<Self, Self::Err> {
172        match Self::parse(s) {
173            Some(colour) => Ok(colour),
174            None => Err(format!("Invalid Colour: {s}")),
175        }
176    }
177}
178
179impl ExtendedColour for Yellow {}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184    use rstest::rstest;
185
186    #[rstest]
187    #[case(Yellow::Gold, "rgb(255,215,0)")]
188    #[case(Yellow::DarkGoldenrod, "rgb(184,134,11)")]
189    #[case(Yellow::Goldenrod, "rgb(218,165,32)")]
190    #[case(Yellow::PaleGoldenrod, "rgb(238,232,170)")]
191    #[case(Yellow::DarkKhaki, "rgb(189,183,107)")]
192    #[case(Yellow::Khaki, "rgb(240,230,140)")]
193    #[case(Yellow::Yellow, "rgb(255,255,0)")]
194    #[case(Yellow::YellowGreen, "rgb(154,205,50)")]
195    #[case(Yellow::PeachPuff, "rgb(255,218,185)")]
196    #[case(Yellow::Moccasin, "rgb(255,228,181)")]
197    #[case(Yellow::PapayaWhip, "rgb(255,239,213)")]
198    #[case(Yellow::LemonChiffon, "rgb(255,250,205)")]
199    #[case(Yellow::LightGoldenrodYellow, "rgb(250,250,210)")]
200    #[case(Yellow::LightYellow, "rgb(255,255,224)")]
201    fn test_rgb_string(#[case] colour: Yellow, #[case] expected: String) {
202        let rgb_colour = colour.to_rgb();
203        let string = rgb_colour.to_string();
204
205        assert_eq!(expected, string);
206    }
207
208    #[rstest]
209    #[case(Yellow::Gold, "FFD700")]
210    #[case(Yellow::DarkGoldenrod, "B8860B")]
211    #[case(Yellow::Goldenrod, "DAA520")]
212    #[case(Yellow::PaleGoldenrod, "EEE8AA")]
213    #[case(Yellow::DarkKhaki, "BDB76B")]
214    #[case(Yellow::Khaki, "F0E68C")]
215    #[case(Yellow::Yellow, "FFFF00")]
216    #[case(Yellow::YellowGreen, "9ACD32")]
217    #[case(Yellow::PeachPuff, "FFDAB9")]
218    #[case(Yellow::Moccasin, "FFE4B5")]
219    #[case(Yellow::PapayaWhip, "FFEFD5")]
220    #[case(Yellow::LemonChiffon, "FFFACD")]
221    #[case(Yellow::LightGoldenrodYellow, "FAFAD2")]
222    #[case(Yellow::LightYellow, "FFFFE0")]
223    fn test_hex_triplet_string(
224        #[case] colour: Yellow,
225        #[values(Prefix::None, Prefix::Hash)] prefix: Prefix,
226        #[case] expected: String,
227    ) {
228        let prefix_string = match prefix {
229            Prefix::None => "".to_string(),
230            Prefix::Hash => "#".to_string(),
231        };
232
233        let expected = format!("{prefix_string}{expected}");
234
235        let hex_colour = colour.to_hex_triplet(prefix);
236
237        assert_eq!(expected, hex_colour);
238    }
239
240    #[rstest]
241    #[case("#ffd700", Yellow::Gold)]
242    #[case("ffd700", Yellow::Gold)]
243    #[case("Gold", Yellow::Gold)]
244    #[case("#b8860b", Yellow::DarkGoldenrod)]
245    #[case("b8860b", Yellow::DarkGoldenrod)]
246    #[case("DarkGoldenRod", Yellow::DarkGoldenrod)]
247    #[case("#dab500", Yellow::Goldenrod)]
248    #[case("dab500", Yellow::Goldenrod)]
249    #[case("GoldenRod", Yellow::Goldenrod)]
250    #[case("#eee8aa", Yellow::PaleGoldenrod)]
251    #[case("eee8aa", Yellow::PaleGoldenrod)]
252    #[case("PaleGoldenRod", Yellow::PaleGoldenrod)]
253    #[case("#bdb76b", Yellow::DarkKhaki)]
254    #[case("bdb76b", Yellow::DarkKhaki)]
255    #[case("DarkKhaki", Yellow::DarkKhaki)]
256    #[case("#f0e68c", Yellow::Khaki)]
257    #[case("f0e68c", Yellow::Khaki)]
258    #[case("Khaki", Yellow::Khaki)]
259    #[case("#ffff00", Yellow::Yellow)]
260    #[case("ffff00", Yellow::Yellow)]
261    #[case("Yellow", Yellow::Yellow)]
262    #[case("#9acd32", Yellow::YellowGreen)]
263    #[case("9acd32", Yellow::YellowGreen)]
264    #[case("YellowGreen", Yellow::YellowGreen)]
265    #[case("#ffdab9", Yellow::PeachPuff)]
266    #[case("ffdab9", Yellow::PeachPuff)]
267    #[case("PeachPuff", Yellow::PeachPuff)]
268    #[case("#ffe4b5", Yellow::Moccasin)]
269    #[case("ffe4b5", Yellow::Moccasin)]
270    #[case("Moccasin", Yellow::Moccasin)]
271    #[case("#ffefd5", Yellow::PapayaWhip)]
272    #[case("ffefd5", Yellow::PapayaWhip)]
273    #[case("PapayaWhip", Yellow::PapayaWhip)]
274    #[case("#fffacd", Yellow::LemonChiffon)]
275    #[case("fffacd", Yellow::LemonChiffon)]
276    #[case("LemonChiffon", Yellow::LemonChiffon)]
277    #[case("#fafad2", Yellow::LightGoldenrodYellow)]
278    #[case("fafad2", Yellow::LightGoldenrodYellow)]
279    #[case("LightGoldenrodYellow", Yellow::LightGoldenrodYellow)]
280    #[case("#ffffe0", Yellow::LightYellow)]
281    #[case("ffffe0", Yellow::LightYellow)]
282    #[case("LightYellow", Yellow::LightYellow)]
283    fn test_from_str(#[case] input: &str, #[case] expected: Yellow) {
284        assert_eq!(expected, Yellow::from_str(input).unwrap())
285    }
286
287    #[rstest]
288    #[case("#ffd700", Some(Yellow::Gold))]
289    #[case("ffd700", Some(Yellow::Gold))]
290    #[case("Gold", Some(Yellow::Gold))]
291    #[case("#b8860b", Some(Yellow::DarkGoldenrod))]
292    #[case("b8860b", Some(Yellow::DarkGoldenrod))]
293    #[case("DarkGoldenRod", Some(Yellow::DarkGoldenrod))]
294    #[case("#dab500", Some(Yellow::Goldenrod))]
295    #[case("dab500", Some(Yellow::Goldenrod))]
296    #[case("GoldenRod", Some(Yellow::Goldenrod))]
297    #[case("#eee8aa", Some(Yellow::PaleGoldenrod))]
298    #[case("eee8aa", Some(Yellow::PaleGoldenrod))]
299    #[case("PaleGoldenRod", Some(Yellow::PaleGoldenrod))]
300    #[case("#bdb76b", Some(Yellow::DarkKhaki))]
301    #[case("bdb76b", Some(Yellow::DarkKhaki))]
302    #[case("DarkKhaki", Some(Yellow::DarkKhaki))]
303    #[case("#f0e68c", Some(Yellow::Khaki))]
304    #[case("f0e68c", Some(Yellow::Khaki))]
305    #[case("Khaki", Some(Yellow::Khaki))]
306    #[case("#ffff00", Some(Yellow::Yellow))]
307    #[case("ffff00", Some(Yellow::Yellow))]
308    #[case("Yellow", Some(Yellow::Yellow))]
309    #[case("#9acd32", Some(Yellow::YellowGreen))]
310    #[case("9acd32", Some(Yellow::YellowGreen))]
311    #[case("YellowGreen", Some(Yellow::YellowGreen))]
312    #[case("#ffdab9", Some(Yellow::PeachPuff))]
313    #[case("ffdab9", Some(Yellow::PeachPuff))]
314    #[case("PeachPuff", Some(Yellow::PeachPuff))]
315    #[case("#ffe4b5", Some(Yellow::Moccasin))]
316    #[case("ffe4b5", Some(Yellow::Moccasin))]
317    #[case("Moccasin", Some(Yellow::Moccasin))]
318    #[case("#ffefd5", Some(Yellow::PapayaWhip))]
319    #[case("ffefd5", Some(Yellow::PapayaWhip))]
320    #[case("PapayaWhip", Some(Yellow::PapayaWhip))]
321    #[case("#fffacd", Some(Yellow::LemonChiffon))]
322    #[case("fffacd", Some(Yellow::LemonChiffon))]
323    #[case("LemonChiffon", Some(Yellow::LemonChiffon))]
324    #[case("#fafad2", Some(Yellow::LightGoldenrodYellow))]
325    #[case("fafad2", Some(Yellow::LightGoldenrodYellow))]
326    #[case("LightGoldenrodYellow", Some(Yellow::LightGoldenrodYellow))]
327    #[case("#ffffe0", Some(Yellow::LightYellow))]
328    #[case("ffffe0", Some(Yellow::LightYellow))]
329    #[case("LightYellow", Some(Yellow::LightYellow))]
330    #[case("012345", None)]
331    fn test_name_colour(#[case] input: &str, #[case] expected: Option<Yellow>) {
332        assert_eq!(expected, Yellow::name_colour(input))
333    }
334}