1 use std::{convert::AsRef, convert::TryFrom, result::Result, str::FromStr};
2 
3 #[cfg(feature = "serde")]
4 use serde::{Deserialize, Serialize};
5 
6 /// Represents a color.
7 ///
8 /// # Platform-specific Notes
9 ///
10 /// The following list of 16 base colors are available for almost all terminals (Windows 7 and 8 included).
11 ///
12 /// | Light | Dark |
13 /// | :--| :--   |
14 /// | `Grey` | `Black` |
15 /// | `Red` | `DarkRed` |
16 /// | `Green` | `DarkGreen` |
17 /// | `Yellow` | `DarkYellow` |
18 /// | `Blue` | `DarkBlue` |
19 /// | `Magenta` | `DarkMagenta` |
20 /// | `Cyan` | `DarkCyan` |
21 /// | `White` | `DarkWhite` |
22 ///
23 /// Most UNIX terminals and Windows 10 consoles support additional colors.
24 /// See [`Color::Rgb`](enum.Color.html#variant.Rgb) or [`Color::AnsiValue`](enum.Color.html#variant.AnsiValue) for
25 /// more info.
26 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27 #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
28 pub enum Color {
29     /// Resets the terminal color.
30     Reset,
31 
32     /// Black color.
33     Black,
34 
35     /// Dark grey color.
36     DarkGrey,
37 
38     /// Light red color.
39     Red,
40 
41     /// Dark red color.
42     DarkRed,
43 
44     /// Light green color.
45     Green,
46 
47     /// Dark green color.
48     DarkGreen,
49 
50     /// Light yellow color.
51     Yellow,
52 
53     /// Dark yellow color.
54     DarkYellow,
55 
56     /// Light blue color.
57     Blue,
58 
59     /// Dark blue color.
60     DarkBlue,
61 
62     /// Light magenta color.
63     Magenta,
64 
65     /// Dark magenta color.
66     DarkMagenta,
67 
68     /// Light cyan color.
69     Cyan,
70 
71     /// Dark cyan color.
72     DarkCyan,
73 
74     /// White color.
75     White,
76 
77     /// Grey color.
78     Grey,
79 
80     /// An RGB color. See [RGB color model](https://en.wikipedia.org/wiki/RGB_color_model) for more info.
81     ///
82     /// Most UNIX terminals and Windows 10 supported only.
83     /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info.
84     Rgb { r: u8, g: u8, b: u8 },
85 
86     /// An ANSI color. See [256 colors - cheat sheet](https://jonasjacek.github.io/colors/) for more info.
87     ///
88     /// Most UNIX terminals and Windows 10 supported only.
89     /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info.
90     AnsiValue(u8),
91 }
92 
93 impl TryFrom<&str> for Color {
94     type Error = ();
95 
96     /// Try to create a `Color` from the string representation. This returns an error if the string does not match.
try_from(src: &str) -> Result<Self, Self::Error>97     fn try_from(src: &str) -> Result<Self, Self::Error> {
98         let src = src.to_lowercase();
99 
100         match src.as_ref() {
101             "black" => Ok(Color::Black),
102             "dark_grey" => Ok(Color::DarkGrey),
103             "red" => Ok(Color::Red),
104             "dark_red" => Ok(Color::DarkRed),
105             "green" => Ok(Color::Green),
106             "dark_green" => Ok(Color::DarkGreen),
107             "yellow" => Ok(Color::Yellow),
108             "dark_yellow" => Ok(Color::DarkYellow),
109             "blue" => Ok(Color::Blue),
110             "dark_blue" => Ok(Color::DarkBlue),
111             "magenta" => Ok(Color::Magenta),
112             "dark_magenta" => Ok(Color::DarkMagenta),
113             "cyan" => Ok(Color::Cyan),
114             "dark_cyan" => Ok(Color::DarkCyan),
115             "white" => Ok(Color::White),
116             "grey" => Ok(Color::Grey),
117             _ => Err(()),
118         }
119     }
120 }
121 
122 impl FromStr for Color {
123     type Err = ();
124 
125     /// Creates a `Color` from the string representation.
126     ///
127     /// # Notes
128     ///
129     /// * Returns `Color::White` in case of an unknown color.
130     /// * Does not return `Err` and you can safely unwrap.
from_str(src: &str) -> Result<Self, Self::Err>131     fn from_str(src: &str) -> Result<Self, Self::Err> {
132         Ok(Color::try_from(src).unwrap_or(Color::White))
133     }
134 }
135 
136 impl From<(u8, u8, u8)> for Color {
137     /// Creates a 'Color' from the tuple representation.
from(val: (u8, u8, u8)) -> Self138     fn from(val: (u8, u8, u8)) -> Self {
139         let (r, g, b) = val;
140         Self::Rgb { r, g, b }
141     }
142 }
143 
144 #[cfg(test)]
145 mod tests {
146     use super::Color;
147 
148     #[test]
test_known_color_conversion()149     fn test_known_color_conversion() {
150         assert_eq!("black".parse(), Ok(Color::Black));
151         assert_eq!("dark_grey".parse(), Ok(Color::DarkGrey));
152         assert_eq!("red".parse(), Ok(Color::Red));
153         assert_eq!("dark_red".parse(), Ok(Color::DarkRed));
154         assert_eq!("green".parse(), Ok(Color::Green));
155         assert_eq!("dark_green".parse(), Ok(Color::DarkGreen));
156         assert_eq!("yellow".parse(), Ok(Color::Yellow));
157         assert_eq!("dark_yellow".parse(), Ok(Color::DarkYellow));
158         assert_eq!("blue".parse(), Ok(Color::Blue));
159         assert_eq!("dark_blue".parse(), Ok(Color::DarkBlue));
160         assert_eq!("magenta".parse(), Ok(Color::Magenta));
161         assert_eq!("dark_magenta".parse(), Ok(Color::DarkMagenta));
162         assert_eq!("cyan".parse(), Ok(Color::Cyan));
163         assert_eq!("dark_cyan".parse(), Ok(Color::DarkCyan));
164         assert_eq!("white".parse(), Ok(Color::White));
165         assert_eq!("grey".parse(), Ok(Color::Grey));
166     }
167 
168     #[test]
test_unknown_color_conversion_yields_white()169     fn test_unknown_color_conversion_yields_white() {
170         assert_eq!("foo".parse(), Ok(Color::White));
171     }
172 
173     #[test]
test_know_rgb_color_conversion()174     fn test_know_rgb_color_conversion() {
175         assert_eq!(Color::from((0, 0, 0)), Color::Rgb { r: 0, g: 0, b: 0 });
176         assert_eq!(
177             Color::from((255, 255, 255)),
178             Color::Rgb {
179                 r: 255,
180                 g: 255,
181                 b: 255
182             }
183         );
184     }
185 }
186