named_colour/ext/
cyan.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 cyan
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumCount)]
16#[allow(missing_docs)]
17pub enum Cyan {
18    MediumAquaMarine,
19    MediumSeaGreen,
20    LightSeaGreen,
21    DarkSlateGray,
22    Teal,
23    DarkCyan,
24    Aqua,
25    Cyan,
26    LightCyan,
27    DarkTurquoise,
28    Turquoise,
29    MediumTurquoise,
30    PaleTurquoise,
31    AquaMarine,
32    Honeydew,
33}
34
35impl fmt::Display for Cyan {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        match self {
38            Self::MediumAquaMarine => write!(f, "#66CDAA"),
39            Self::MediumSeaGreen => write!(f, "#3CB371"),
40            Self::LightSeaGreen => write!(f, "#20B2AA"),
41            Self::DarkSlateGray => write!(f, "#2F4F4F"),
42            Self::Teal => write!(f, "#008080"),
43            Self::DarkCyan => write!(f, "#008B8B"),
44            Self::Aqua => write!(f, "#00FFFF"),
45            Self::Cyan => write!(f, "#00FFFF"),
46            Self::LightCyan => write!(f, "#E0FFFF"),
47            Self::DarkTurquoise => write!(f, "#00CED1"),
48            Self::Turquoise => write!(f, "#40E0D0"),
49            Self::MediumTurquoise => write!(f, "#48D1CC"),
50            Self::PaleTurquoise => write!(f, "#AFEEEE"),
51            Self::AquaMarine => write!(f, "#7FFFD4"),
52            Self::Honeydew => write!(f, "#F0FFF0"),
53        }
54    }
55}
56
57impl Cyan {
58    /// Display the colour name as an RGB Tuple
59    ///
60    /// ## Example
61    ///
62    ///```
63    /// # use named_colour::ext::Cyan;
64    /// # fn main() {
65    ///    let colour = Cyan::Teal;
66    ///    let rgb_colour = colour.to_rgb();
67    ///
68    ///    let string = rgb_colour.to_string();
69    ///    assert_eq!("rgb(0,128,128)", string);
70    ///
71    ///  # }
72    ///```
73    pub fn to_rgb(&self) -> Rgb<u8> {
74        let colour = self.to_string();
75
76        let r: u8 = u8::from_str_radix(&colour[1..3], 16).unwrap();
77        let g: u8 = u8::from_str_radix(&colour[3..5], 16).unwrap();
78        let b: u8 = u8::from_str_radix(&colour[5..7], 16).unwrap();
79
80        Rgb::new(r, g, b)
81    }
82
83    /// Display the colour name as an RGB Tuple
84    ///
85    /// ## Example
86    ///
87    ///```
88    /// # use named_colour::ext::Cyan;
89    /// # use named_colour::Prefix;
90    ///    let colour = Cyan::Teal;
91    ///
92    ///     assert_eq!("#008080", colour.to_hex_triplet(Prefix::Hash));
93    ///
94    ///```
95    pub fn to_hex_triplet(&self, prefix: Prefix) -> String {
96        let rgb = self.to_rgb();
97
98        let prefix = match prefix {
99            Prefix::Hash => "#",
100            Prefix::None => "",
101        };
102
103        format!("{}{:02X}{:02X}{:02X}", prefix, rgb.r, rgb.g, rgb.b)
104    }
105
106    /// Parse a colour from string
107    ///
108    /// ## Example
109    ///
110    ///```
111    /// # use named_colour::ext::Cyan;
112    /// # use named_colour::Prefix;
113    ///    let colour = Cyan::Teal;
114    ///
115    ///     assert_eq!(Some(Cyan::Teal), Cyan::parse("teal"));
116    ///
117    ///```
118    pub fn parse(name: &str) -> Option<Self> {
119        match name.to_lowercase().as_str() {
120            "#66cdaa" | "66cdaa" | "mediumaquamarine" => Some(Self::MediumAquaMarine),
121            "#3cb371" | "3cb371" | "mediumseagreen" => Some(Self::MediumSeaGreen),
122            "#20b2aa" | "20b2aa" | "lightseagreen" => Some(Self::LightSeaGreen),
123            "#2f4f4f" | "2f4f4f" | "darkslategray" => Some(Self::DarkSlateGray),
124            "#008080" | "008080" | "teal" => Some(Self::Teal),
125            "#008b8b" | "008b8b" | "darkcyan" => Some(Self::DarkCyan),
126            "#00ffff" | "00ffff" | "aqua" => Some(Self::Aqua),
127            "cyan" => Some(Self::Cyan),
128            "#e0ffff" | "e0ffff" | "lightcyan" => Some(Self::LightCyan),
129            "#00ced1" | "00ced1" | "darkturquoise" => Some(Self::DarkTurquoise),
130            "#40e0d0" | "40e0d0" | "turquoise" => Some(Self::Turquoise),
131            "#48d1cc" | "48d1cc" | "mediumturquoise" => Some(Self::MediumTurquoise),
132            "#afeeee" | "afeeee" | "paleturquoise" => Some(Self::PaleTurquoise),
133            "#7fffd4" | "7fffd4" | "aquamarine" => Some(Self::AquaMarine),
134            "#f0fff0" | "f0fff0" | "honeydew" => Some(Self::Honeydew),
135            _ => None,
136        }
137    }
138
139    /// Generate a random colour
140    ///     
141    /// ## Example
142    ///
143    ///```
144    /// # use named_colour::ext::Cyan;
145    /// # fn main() {
146    ///    let colour = Cyan::random();
147    ///
148    /// # }
149    /// ```
150    pub fn random() -> Self {
151        let mut rand = StdRand::default();
152
153        match rand.next_range(0..Self::COUNT) {
154            0 => Self::MediumAquaMarine,
155            1 => Self::MediumSeaGreen,
156            2 => Self::LightSeaGreen,
157            3 => Self::DarkSlateGray,
158            4 => Self::Teal,
159            5 => Self::DarkCyan,
160            6 => Self::Aqua,
161            7 => Self::Cyan,
162            8 => Self::LightCyan,
163            9 => Self::DarkTurquoise,
164            10 => Self::Turquoise,
165            11 => Self::MediumTurquoise,
166            12 => Self::PaleTurquoise,
167            13 => Self::AquaMarine,
168            14 => Self::Honeydew,
169            _ => Self::Cyan,
170        }
171    }
172}
173
174impl FromStr for Cyan {
175    type Err = String;
176    fn from_str(s: &str) -> Result<Self, Self::Err> {
177        match Self::parse(s) {
178            Some(colour) => Ok(colour),
179            None => Err(format!("Invalid Colour: {s}")),
180        }
181    }
182}
183
184impl ExtendedColour for Cyan {}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189    use rstest::rstest;
190
191    #[rstest]
192    #[case(Cyan::MediumAquaMarine, "rgb(102,205,170)")]
193    #[case(Cyan::MediumSeaGreen, "rgb(60,179,113)")]
194    #[case(Cyan::LightSeaGreen, "rgb(32,178,170)")]
195    #[case(Cyan::DarkSlateGray, "rgb(47,79,79)")]
196    #[case(Cyan::Teal, "rgb(0,128,128)")]
197    #[case(Cyan::DarkCyan, "rgb(0,139,139)")]
198    #[case(Cyan::Aqua, "rgb(0,255,255)")]
199    #[case(Cyan::Cyan, "rgb(0,255,255)")]
200    #[case(Cyan::LightCyan, "rgb(224,255,255)")]
201    #[case(Cyan::DarkTurquoise, "rgb(0,206,209)")]
202    #[case(Cyan::Turquoise, "rgb(64,224,208)")]
203    #[case(Cyan::MediumTurquoise, "rgb(72,209,204)")]
204    #[case(Cyan::PaleTurquoise, "rgb(175,238,238)")]
205    #[case(Cyan::AquaMarine, "rgb(127,255,212)")]
206    #[case(Cyan::Honeydew, "rgb(240,255,240)")]
207    fn test_rgb_string(#[case] colour: Cyan, #[case] expected: String) {
208        let rgb_colour = colour.to_rgb();
209        let string = rgb_colour.to_string();
210
211        assert_eq!(expected, string);
212    }
213
214    #[rstest]
215    #[case(Cyan::MediumAquaMarine, "66CDAA")]
216    #[case(Cyan::MediumSeaGreen, "3CB371")]
217    #[case(Cyan::LightSeaGreen, "20B2AA")]
218    #[case(Cyan::DarkSlateGray, "2F4F4F")]
219    #[case(Cyan::Teal, "008080")]
220    #[case(Cyan::DarkCyan, "008B8B")]
221    #[case(Cyan::Aqua, "00FFFF")]
222    #[case(Cyan::Cyan, "00FFFF")]
223    #[case(Cyan::LightCyan, "E0FFFF")]
224    #[case(Cyan::DarkTurquoise, "00CED1")]
225    #[case(Cyan::Turquoise, "40E0D0")]
226    #[case(Cyan::MediumTurquoise, "48D1CC")]
227    #[case(Cyan::PaleTurquoise, "AFEEEE")]
228    #[case(Cyan::AquaMarine, "7FFFD4")]
229    #[case(Cyan::Honeydew, "F0FFF0")]
230    fn test_hex_triplet_string(
231        #[case] colour: Cyan,
232        #[values(Prefix::None, Prefix::Hash)] prefix: Prefix,
233        #[case] expected: String,
234    ) {
235        let prefix_string = match prefix {
236            Prefix::None => "".to_string(),
237            Prefix::Hash => "#".to_string(),
238        };
239
240        let expected = format!("{prefix_string}{expected}");
241
242        let hex_colour = colour.to_hex_triplet(prefix);
243
244        assert_eq!(expected, hex_colour);
245    }
246
247    #[rstest]
248    #[case("#66cdaa", Cyan::MediumAquaMarine)]
249    #[case("66cdaa", Cyan::MediumAquaMarine)]
250    #[case("mediumaquamarine", Cyan::MediumAquaMarine)]
251    #[case("#3cb371", Cyan::MediumSeaGreen)]
252    #[case("3cb371", Cyan::MediumSeaGreen)]
253    #[case("mediumseagreen", Cyan::MediumSeaGreen)]
254    #[case("#20b2aa", Cyan::LightSeaGreen)]
255    #[case("20b2aa", Cyan::LightSeaGreen)]
256    #[case("lightseagreen", Cyan::LightSeaGreen)]
257    #[case("#2f4f4f", Cyan::DarkSlateGray)]
258    #[case("2f4f4f", Cyan::DarkSlateGray)]
259    #[case("darkslategray", Cyan::DarkSlateGray)]
260    #[case("#008080", Cyan::Teal)]
261    #[case("008080", Cyan::Teal)]
262    #[case("teal", Cyan::Teal)]
263    #[case("#008b8b", Cyan::DarkCyan)]
264    #[case("008b8b", Cyan::DarkCyan)]
265    #[case("darkcyan", Cyan::DarkCyan)]
266    #[case("#00ffff", Cyan::Aqua)]
267    #[case("00ffff", Cyan::Aqua)]
268    #[case("aqua", Cyan::Aqua)]
269    #[case("cyan", Cyan::Cyan)]
270    #[case("#e0ffff", Cyan::LightCyan)]
271    #[case("e0ffff", Cyan::LightCyan)]
272    #[case("lightcyan", Cyan::LightCyan)]
273    #[case("#00ced1", Cyan::DarkTurquoise)]
274    #[case("00ced1", Cyan::DarkTurquoise)]
275    #[case("darkturquoise", Cyan::DarkTurquoise)]
276    #[case("#40e0d0", Cyan::Turquoise)]
277    #[case("40e0d0", Cyan::Turquoise)]
278    #[case("turquoise", Cyan::Turquoise)]
279    #[case("#48d1cc", Cyan::MediumTurquoise)]
280    #[case("48d1cc", Cyan::MediumTurquoise)]
281    #[case("mediumturquoise", Cyan::MediumTurquoise)]
282    #[case("#afeeee", Cyan::PaleTurquoise)]
283    #[case("afeeee", Cyan::PaleTurquoise)]
284    #[case("paleturquoise", Cyan::PaleTurquoise)]
285    #[case("#7fffd4", Cyan::AquaMarine)]
286    #[case("7fffd4", Cyan::AquaMarine)]
287    #[case("aquamarine", Cyan::AquaMarine)]
288    #[case("#f0fff0", Cyan::Honeydew)]
289    #[case("f0fff0", Cyan::Honeydew)]
290    #[case("honeydew", Cyan::Honeydew)]
291    fn test_from_str(#[case] input: &str, #[case] expected: Cyan) {
292        assert_eq!(expected, Cyan::from_str(input).unwrap())
293    }
294
295    #[rstest]
296    #[case("#66cdaa", Some(Cyan::MediumAquaMarine))]
297    #[case("66cdaa", Some(Cyan::MediumAquaMarine))]
298    #[case("mediumaquamarine", Some(Cyan::MediumAquaMarine))]
299    #[case("#3cb371", Some(Cyan::MediumSeaGreen))]
300    #[case("3cb371", Some(Cyan::MediumSeaGreen))]
301    #[case("mediumseagreen", Some(Cyan::MediumSeaGreen))]
302    #[case("#20b2aa", Some(Cyan::LightSeaGreen))]
303    #[case("20b2aa", Some(Cyan::LightSeaGreen))]
304    #[case("lightseagreen", Some(Cyan::LightSeaGreen))]
305    #[case("#2f4f4f", Some(Cyan::DarkSlateGray))]
306    #[case("2f4f4f", Some(Cyan::DarkSlateGray))]
307    #[case("darkslategray", Some(Cyan::DarkSlateGray))]
308    #[case("#008080", Some(Cyan::Teal))]
309    #[case("008080", Some(Cyan::Teal))]
310    #[case("teal", Some(Cyan::Teal))]
311    #[case("#008b8b", Some(Cyan::DarkCyan))]
312    #[case("008b8b", Some(Cyan::DarkCyan))]
313    #[case("darkcyan", Some(Cyan::DarkCyan))]
314    #[case("#00ffff", Some(Cyan::Aqua))]
315    #[case("00ffff", Some(Cyan::Aqua))]
316    #[case("aqua", Some(Cyan::Aqua))]
317    #[case("cyan", Some(Cyan::Cyan))]
318    #[case("#e0ffff", Some(Cyan::LightCyan))]
319    #[case("e0ffff", Some(Cyan::LightCyan))]
320    #[case("lightcyan", Some(Cyan::LightCyan))]
321    #[case("#00ced1", Some(Cyan::DarkTurquoise))]
322    #[case("00ced1", Some(Cyan::DarkTurquoise))]
323    #[case("darkturquoise", Some(Cyan::DarkTurquoise))]
324    #[case("#40e0d0", Some(Cyan::Turquoise))]
325    #[case("40e0d0", Some(Cyan::Turquoise))]
326    #[case("turquoise", Some(Cyan::Turquoise))]
327    #[case("#48d1cc", Some(Cyan::MediumTurquoise))]
328    #[case("48d1cc", Some(Cyan::MediumTurquoise))]
329    #[case("mediumturquoise", Some(Cyan::MediumTurquoise))]
330    #[case("#afeeee", Some(Cyan::PaleTurquoise))]
331    #[case("afeeee", Some(Cyan::PaleTurquoise))]
332    #[case("paleturquoise", Some(Cyan::PaleTurquoise))]
333    #[case("#7fffd4", Some(Cyan::AquaMarine))]
334    #[case("7fffd4", Some(Cyan::AquaMarine))]
335    #[case("aquamarine", Some(Cyan::AquaMarine))]
336    #[case("#f0fff0", Some(Cyan::Honeydew))]
337    #[case("f0fff0", Some(Cyan::Honeydew))]
338    #[case("honeydew", Some(Cyan::Honeydew))]
339    #[case("012345", None)]
340    fn test_name_colour(#[case] input: &str, #[case] expected: Option<Cyan>) {
341        assert_eq!(expected, Cyan::name_colour(input))
342    }
343}