named_colour/ext/
green.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 green
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount)]
16#[allow(missing_docs)]
17pub enum Green {
18    YellowGreen,
19    DarkOliveGreen,
20    Olive,
21    OliveDrab,
22    LawnGreen,
23    ChartReuse,
24    GreenYellow,
25    DarkGreen,
26    Green,
27    ForestGreen,
28    Lime,
29    LimeGreen,
30    LightGreen,
31    PaleGreen,
32    DarkSeaGreen,
33    MediumSpringGreen,
34    SpringGreen,
35    SeaGreen,
36}
37
38impl fmt::Display for Green {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::YellowGreen => write!(f, "#9ACD32"),
42            Self::DarkOliveGreen => write!(f, "#556B2F"),
43            Self::Olive => write!(f, "#808000"),
44            Self::OliveDrab => write!(f, "#6B8E23"),
45            Self::LawnGreen => write!(f, "#7CFC00"),
46            Self::ChartReuse => write!(f, "#7FFF00"),
47            Self::GreenYellow => write!(f, "#ADFF2F"),
48            Self::DarkGreen => write!(f, "#006400"),
49            Self::Green => write!(f, "#008000"),
50            Self::ForestGreen => write!(f, "#228B22"),
51            Self::Lime => write!(f, "#00FF00"),
52            Self::LimeGreen => write!(f, "#32CD32"),
53            Self::LightGreen => write!(f, "#90EE90"),
54            Self::PaleGreen => write!(f, "#98FB98"),
55            Self::DarkSeaGreen => write!(f, "#8FBC8F"),
56            Self::MediumSpringGreen => write!(f, "#00FA9A"),
57            Self::SpringGreen => write!(f, "#00FF7F"),
58            Self::SeaGreen => write!(f, "#2E8B57"),
59        }
60    }
61}
62
63impl Green {
64    /// Display the colour name as an RGB Tuple
65    ///
66    /// ## Example
67    ///
68    ///```
69    /// # use named_colour::ext::Green;
70    /// # fn main() {
71    ///    let colour = Green::LawnGreen;
72    ///    let rgb_colour = colour.to_rgb();
73    ///
74    ///    let string = rgb_colour.to_string();
75    ///    assert_eq!("rgb(124,252,0)", string);
76    ///
77    ///  # }
78    ///```
79    pub fn to_rgb(&self) -> Rgb<u8> {
80        let colour = self.to_string();
81
82        let r: u8 = u8::from_str_radix(&colour[1..3], 16).unwrap();
83        let g: u8 = u8::from_str_radix(&colour[3..5], 16).unwrap();
84        let b: u8 = u8::from_str_radix(&colour[5..7], 16).unwrap();
85
86        Rgb::new(r, g, b)
87    }
88
89    /// Display the colour name as an RGB Tuple
90    ///
91    /// ## Example
92    ///
93    ///```
94    /// # use named_colour::ext::Green;
95    /// # use named_colour::Prefix;
96    ///    let colour = Green::LawnGreen;
97    ///
98    ///     assert_eq!("#7CFC00", colour.to_hex_triplet(Prefix::Hash));
99    ///
100    ///```
101    pub fn to_hex_triplet(&self, prefix: Prefix) -> String {
102        let rgb = self.to_rgb();
103
104        let prefix = match prefix {
105            Prefix::Hash => "#",
106            Prefix::None => "",
107        };
108
109        format!("{}{:02X}{:02X}{:02X}", prefix, rgb.r, rgb.g, rgb.b)
110    }
111    /// Parse a colour from string
112    ///
113    /// ## Example
114    ///
115    ///```
116    /// # use named_colour::ext::Green;
117    /// # fn main() {
118    ///    let colour = Green::parse("#7CFC00");
119    ///    assert_eq!(Some(Green::LawnGreen), colour);
120    ///
121    ///  # }
122    ///```
123    pub fn parse(name: &str) -> Option<Self> {
124        match name.to_lowercase().as_str() {
125            "#9acd32" | "9acd32" | "yellowgreen" => Some(Self::YellowGreen),
126            "#556b2f" | "556b2f" | "darkolivegreen" => Some(Self::DarkOliveGreen),
127            "#808000" | "808000" | "olive" => Some(Self::Olive),
128            "#6b8e23" | "6b8e23" | "olivedrab" => Some(Self::OliveDrab),
129            "#7cfc00" | "7cfc00" | "lawngreen" => Some(Self::LawnGreen),
130            "#7fff00" | "7fff00" | "chartreuse" => Some(Self::ChartReuse),
131            "#adff2f" | "adff2f" | "greenyellow" => Some(Self::GreenYellow),
132            "#006400" | "006400" | "darkgreen" => Some(Self::DarkGreen),
133            "#008000" | "008000" | "green" => Some(Self::Green),
134            "#228b22" | "228b22" | "forestgreen" => Some(Self::ForestGreen),
135            "#32cd32" | "32cd32" | "limegreen" => Some(Self::LimeGreen),
136            "#90ee90" | "90ee90" | "lightgreen" => Some(Self::LightGreen),
137            "#98fb98" | "98fb98" | "palegreen" => Some(Self::PaleGreen),
138            "#8fbc8f" | "8fbc8f" | "darkseagreen" => Some(Self::DarkSeaGreen),
139            "#00fa9a" | "00fa9a" | "mediumspringgreen" => Some(Self::MediumSpringGreen),
140            "#00ff7f" | "00ff7f" | "springgreen" => Some(Self::SpringGreen),
141            "#2e8b57" | "2e8b57" | "seagreen" => Some(Self::SeaGreen),
142            "#00ff00" | "00ff00" | "lime" => Some(Self::Lime),
143            _ => None,
144        }
145    }
146
147    /// Generate a random colour
148    ///     
149    /// ## Example
150    ///
151    ///```
152    /// # use named_colour::ext::Green;
153    /// # fn main() {
154    ///    let colour = Green::random();
155    ///
156    /// # }
157    /// ```
158    pub fn random() -> Self {
159        let mut rand = StdRand::default();
160
161        match rand.next_range(0..Self::COUNT) {
162            0 => Self::YellowGreen,
163            1 => Self::DarkOliveGreen,
164            2 => Self::Olive,
165            3 => Self::OliveDrab,
166            4 => Self::LawnGreen,
167            5 => Self::ChartReuse,
168            6 => Self::GreenYellow,
169            7 => Self::DarkGreen,
170            8 => Self::Green,
171            9 => Self::ForestGreen,
172            10 => Self::Lime,
173            11 => Self::LimeGreen,
174            12 => Self::LightGreen,
175            13 => Self::PaleGreen,
176            14 => Self::DarkSeaGreen,
177            15 => Self::MediumSpringGreen,
178            16 => Self::SpringGreen,
179            17 => Self::SeaGreen,
180            _ => Self::Green,
181        }
182    }
183}
184
185impl FromStr for Green {
186    type Err = String;
187    fn from_str(s: &str) -> Result<Self, Self::Err> {
188        match Self::parse(s) {
189            Some(colour) => Ok(colour),
190            None => Err(format!("Invalid Colour: {}", s)),
191        }
192    }
193}
194
195impl ExtendedColour for Green {}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200    use rstest::rstest;
201
202    #[rstest]
203    #[case(Green::YellowGreen, "rgb(154,205,50)")]
204    #[case(Green::DarkOliveGreen, "rgb(85,107,47)")]
205    #[case(Green::OliveDrab, "rgb(107,142,35)")]
206    #[case(Green::LawnGreen, "rgb(124,252,0)")]
207    #[case(Green::ChartReuse, "rgb(127,255,0)")]
208    #[case(Green::GreenYellow, "rgb(173,255,47)")]
209    #[case(Green::DarkGreen, "rgb(0,100,0)")]
210    #[case(Green::Green, "rgb(0,128,0)")]
211    #[case(Green::ForestGreen, "rgb(34,139,34)")]
212    #[case(Green::Lime, "rgb(0,255,0)")]
213    #[case(Green::LimeGreen, "rgb(50,205,50)")]
214    #[case(Green::LightGreen, "rgb(144,238,144)")]
215    #[case(Green::PaleGreen, "rgb(152,251,152)")]
216    #[case(Green::DarkSeaGreen, "rgb(143,188,143)")]
217    #[case(Green::MediumSpringGreen, "rgb(0,250,154)")]
218    #[case(Green::SpringGreen, "rgb(0,255,127)")]
219    #[case(Green::SeaGreen, "rgb(46,139,87)")]
220    fn test_rgb_string(#[case] colour: Green, #[case] expected: String) {
221        let rgb_colour = colour.to_rgb();
222        let string = rgb_colour.to_string();
223
224        assert_eq!(expected, string);
225    }
226
227    #[rstest]
228    #[case(Green::YellowGreen, "9ACD32")]
229    #[case(Green::DarkOliveGreen, "556B2F")]
230    #[case(Green::OliveDrab, "6B8E23")]
231    #[case(Green::LawnGreen, "7CFC00")]
232    #[case(Green::ChartReuse, "7FFF00")]
233    #[case(Green::GreenYellow, "ADFF2F")]
234    #[case(Green::DarkGreen, "006400")]
235    #[case(Green::Green, "008000")]
236    #[case(Green::ForestGreen, "228B22")]
237    #[case(Green::Lime, "00FF00")]
238    #[case(Green::LimeGreen, "32CD32")]
239    #[case(Green::LightGreen, "90EE90")]
240    #[case(Green::PaleGreen, "98FB98")]
241    #[case(Green::DarkSeaGreen, "8FBC8F")]
242    #[case(Green::MediumSpringGreen, "00FA9A")]
243    #[case(Green::SpringGreen, "00FF7F")]
244    #[case(Green::SeaGreen, "2E8B57")]
245    fn test_hex_triplet_string(
246        #[case] colour: Green,
247        #[values(Prefix::None, Prefix::Hash)] prefix: Prefix,
248        #[case] expected: String,
249    ) {
250        let prefix_string = match prefix {
251            Prefix::None => "".to_string(),
252            Prefix::Hash => "#".to_string(),
253        };
254
255        let expected = format!("{}{}", prefix_string, expected);
256
257        let hex_colour = colour.to_hex_triplet(prefix);
258
259        assert_eq!(expected, hex_colour);
260    }
261
262    #[rstest]
263    #[case("#9acd32", Green::YellowGreen)]
264    #[case("9acd32", Green::YellowGreen)]
265    #[case("yellowgreen", Green::YellowGreen)]
266    #[case("#556b2f", Green::DarkOliveGreen)]
267    #[case("556b2f", Green::DarkOliveGreen)]
268    #[case("darkolivegreen", Green::DarkOliveGreen)]
269    #[case("#808000", Green::Olive)]
270    #[case("808000", Green::Olive)]
271    #[case("olive", Green::Olive)]
272    #[case("#6b8e23", Green::OliveDrab)]
273    #[case("6b8e23", Green::OliveDrab)]
274    #[case("olivedrab", Green::OliveDrab)]
275    #[case("#7cfc00", Green::LawnGreen)]
276    #[case("7cfc00", Green::LawnGreen)]
277    #[case("lawngreen", Green::LawnGreen)]
278    #[case("#7fff00", Green::ChartReuse)]
279    #[case("7fff00", Green::ChartReuse)]
280    #[case("chartreuse", Green::ChartReuse)]
281    #[case("#adff2f", Green::GreenYellow)]
282    #[case("adff2f", Green::GreenYellow)]
283    #[case("greenyellow", Green::GreenYellow)]
284    #[case("#008000", Green::Green)]
285    #[case("008000", Green::Green)]
286    #[case("green", Green::Green)]
287    #[case("#228b22", Green::ForestGreen)]
288    #[case("228b22", Green::ForestGreen)]
289    #[case("forestgreen", Green::ForestGreen)]
290    #[case("#00ff7f", Green::SpringGreen)]
291    #[case("00ff7f", Green::SpringGreen)]
292    #[case("springgreen", Green::SpringGreen)]
293    #[case("#98fb98", Green::PaleGreen)]
294    #[case("98fb98", Green::PaleGreen)]
295    #[case("palegreen", Green::PaleGreen)]
296    #[case("#8fbc8f", Green::DarkSeaGreen)]
297    #[case("8fbc8f", Green::DarkSeaGreen)]
298    #[case("darkseagreen", Green::DarkSeaGreen)]
299    #[case("#00fa9a", Green::MediumSpringGreen)]
300    #[case("00fa9a", Green::MediumSpringGreen)]
301    #[case("mediumspringgreen", Green::MediumSpringGreen)]
302    #[case("#2e8b57", Green::SeaGreen)]
303    #[case("2e8b57", Green::SeaGreen)]
304    #[case("seagreen", Green::SeaGreen)]
305    fn test_from_str(#[case] input: &str, #[case] expected: Green) {
306        assert_eq!(expected, Green::from_str(input).unwrap())
307    }
308
309    #[rstest]
310    #[case("#9acd32", Some(Green::YellowGreen))]
311    #[case("9acd32", Some(Green::YellowGreen))]
312    #[case("yellowgreen", Some(Green::YellowGreen))]
313    #[case("#556b2f", Some(Green::DarkOliveGreen))]
314    #[case("556b2f", Some(Green::DarkOliveGreen))]
315    #[case("darkolivegreen", Some(Green::DarkOliveGreen))]
316    #[case("#808000", Some(Green::Olive))]
317    #[case("808000", Some(Green::Olive))]
318    #[case("olive", Some(Green::Olive))]
319    #[case("#6b8e23", Some(Green::OliveDrab))]
320    #[case("6b8e23", Some(Green::OliveDrab))]
321    #[case("olivedrab", Some(Green::OliveDrab))]
322    #[case("#7cfc00", Some(Green::LawnGreen))]
323    #[case("7cfc00", Some(Green::LawnGreen))]
324    #[case("lawngreen", Some(Green::LawnGreen))]
325    #[case("#7fff00", Some(Green::ChartReuse))]
326    #[case("7fff00", Some(Green::ChartReuse))]
327    #[case("chartreuse", Some(Green::ChartReuse))]
328    #[case("#adff2f", Some(Green::GreenYellow))]
329    #[case("adff2f", Some(Green::GreenYellow))]
330    #[case("greenyellow", Some(Green::GreenYellow))]
331    #[case("#008000", Some(Green::Green))]
332    #[case("008000", Some(Green::Green))]
333    #[case("green", Some(Green::Green))]
334    #[case("#228b22", Some(Green::ForestGreen))]
335    #[case("228b22", Some(Green::ForestGreen))]
336    #[case("forestgreen", Some(Green::ForestGreen))]
337    #[case("#00ff7f", Some(Green::SpringGreen))]
338    #[case("00ff7f", Some(Green::SpringGreen))]
339    #[case("springgreen", Some(Green::SpringGreen))]
340    #[case("#98fb98", Some(Green::PaleGreen))]
341    #[case("98fb98", Some(Green::PaleGreen))]
342    #[case("palegreen", Some(Green::PaleGreen))]
343    #[case("#8fbc8f", Some(Green::DarkSeaGreen))]
344    #[case("8fbc8f", Some(Green::DarkSeaGreen))]
345    #[case("darkseagreen", Some(Green::DarkSeaGreen))]
346    #[case("#00fa9a", Some(Green::MediumSpringGreen))]
347    #[case("00fa9a", Some(Green::MediumSpringGreen))]
348    #[case("mediumspringgreen", Some(Green::MediumSpringGreen))]
349    #[case("#2e8b57", Some(Green::SeaGreen))]
350    #[case("2e8b57", Some(Green::SeaGreen))]
351    #[case("seagreen", Some(Green::SeaGreen))]
352    #[case("012345", None)]
353    fn test_name_colour(#[case] input: &str, #[case] expected: Option<Green>) {
354        assert_eq!(expected, Green::name_colour(input))
355    }
356}