1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
4pub enum AnsiColor {
11 #[default]
12 Black = 0,
14 Red,
16 Green,
18 Yellow,
20 Blue,
22 Magenta,
24 Cyan,
26 White,
28 BrightBlack,
30 BrightRed,
32 BrightGreen,
34 BrightYellow,
36 BrightBlue,
38 BrightMagenta,
40 BrightCyan,
42 BrightWhite,
44}
45
46impl AnsiColor {
47 #[must_use]
49 pub const fn to_index(self) -> u8 {
50 self as u8
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct InvalidAnsiIndex(pub u8);
57
58impl core::fmt::Display for InvalidAnsiIndex {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 write!(f, "invalid ANSI color index: {}", self.0)
61 }
62}
63
64impl TryFrom<u8> for AnsiColor {
65 type Error = InvalidAnsiIndex;
66
67 fn try_from(v: u8) -> Result<Self, Self::Error> {
68 match v {
69 0 => Ok(Self::Black),
70 1 => Ok(Self::Red),
71 2 => Ok(Self::Green),
72 3 => Ok(Self::Yellow),
73 4 => Ok(Self::Blue),
74 5 => Ok(Self::Magenta),
75 6 => Ok(Self::Cyan),
76 7 => Ok(Self::White),
77 8 => Ok(Self::BrightBlack),
78 9 => Ok(Self::BrightRed),
79 10 => Ok(Self::BrightGreen),
80 11 => Ok(Self::BrightYellow),
81 12 => Ok(Self::BrightBlue),
82 13 => Ok(Self::BrightMagenta),
83 14 => Ok(Self::BrightCyan),
84 15 => Ok(Self::BrightWhite),
85 _ => Err(InvalidAnsiIndex(v)),
86 }
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
91pub enum Color {
93 #[default]
94 Default,
99 Ansi(AnsiColor),
103 Indexed(u8),
105 Rgb {
109 r: u8,
111 g: u8,
113 b: u8,
115 },
116}
117
118impl Color {
119 pub const BLACK: Self = Self::Ansi(AnsiColor::Black);
121 pub const RED: Self = Self::Ansi(AnsiColor::Red);
123 pub const GREEN: Self = Self::Ansi(AnsiColor::Green);
125 pub const YELLOW: Self = Self::Ansi(AnsiColor::Yellow);
127 pub const BLUE: Self = Self::Ansi(AnsiColor::Blue);
129 pub const MAGENTA: Self = Self::Ansi(AnsiColor::Magenta);
131 pub const CYAN: Self = Self::Ansi(AnsiColor::Cyan);
133 pub const WHITE: Self = Self::Ansi(AnsiColor::White);
135 pub const BRIGHT_BLACK: Self = Self::Ansi(AnsiColor::BrightBlack);
137 pub const BRIGHT_RED: Self = Self::Ansi(AnsiColor::BrightRed);
139 pub const BRIGHT_GREEN: Self = Self::Ansi(AnsiColor::BrightGreen);
141 pub const BRIGHT_YELLOW: Self = Self::Ansi(AnsiColor::BrightYellow);
143 pub const BRIGHT_BLUE: Self = Self::Ansi(AnsiColor::BrightBlue);
145 pub const BRIGHT_MAGENTA: Self = Self::Ansi(AnsiColor::BrightMagenta);
147 pub const BRIGHT_CYAN: Self = Self::Ansi(AnsiColor::BrightCyan);
149 pub const BRIGHT_WHITE: Self = Self::Ansi(AnsiColor::BrightWhite);
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_color_defaults() {
159 assert_eq!(Color::default(), Color::Default);
160 }
161
162 #[test]
163 fn test_ansi_values() {
164 assert_eq!(AnsiColor::Red as u8, 1);
165 assert_eq!(AnsiColor::BrightWhite as u8, 15);
166 }
167
168 #[test]
169 fn test_ansi_try_from_roundtrip() {
170 for i in 0u8..16 {
171 let color = AnsiColor::try_from(i).expect("should be valid");
172 assert_eq!(color.to_index(), i);
173 }
174 }
175
176 #[test]
177 fn test_ansi_try_from_invalid() {
178 assert_eq!(AnsiColor::try_from(16), Err(InvalidAnsiIndex(16)));
179 assert_eq!(AnsiColor::try_from(255), Err(InvalidAnsiIndex(255)));
180 }
181}