Skip to main content

rs_teststand/expression/constant/
color.rs

1//! Named color constants of the expression language.
2
3/// Named color constants of the expression language.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum ColorConstant {
6    /// `tsBlack`.
7    Black,
8    /// `tsWhite`.
9    White,
10    /// `tsRed`.
11    Red,
12    /// `tsGreen`.
13    Green,
14    /// `tsBlue`.
15    Blue,
16    /// `tsYellow`.
17    Yellow,
18    /// `tsCyan`.
19    Cyan,
20    /// `tsMagenta`.
21    Magenta,
22    /// `tsGray`.
23    Gray,
24    /// `tsDarkRed`.
25    DarkRed,
26    /// `tsDarkGreen`.
27    DarkGreen,
28    /// `tsDarkBlue`.
29    DarkBlue,
30    /// `tsDarkYellow`.
31    DarkYellow,
32    /// `tsDarkCyan`.
33    DarkCyan,
34    /// `tsDarkMagenta`.
35    DarkMagenta,
36    /// `tsLightGray`.
37    LightGray,
38    /// `tsDarkGray`.
39    DarkGray,
40}
41
42impl ColorConstant {
43    /// Every value in this family.
44    pub const ALL: [Self; 17] = [
45        Self::Black,
46        Self::White,
47        Self::Red,
48        Self::Green,
49        Self::Blue,
50        Self::Yellow,
51        Self::Cyan,
52        Self::Magenta,
53        Self::Gray,
54        Self::DarkRed,
55        Self::DarkGreen,
56        Self::DarkBlue,
57        Self::DarkYellow,
58        Self::DarkCyan,
59        Self::DarkMagenta,
60        Self::LightGray,
61        Self::DarkGray,
62    ];
63
64    /// The name as written in an expression.
65    #[must_use]
66    pub const fn name(self) -> &'static str {
67        match self {
68            Self::Black => "tsBlack",
69            Self::White => "tsWhite",
70            Self::Red => "tsRed",
71            Self::Green => "tsGreen",
72            Self::Blue => "tsBlue",
73            Self::Yellow => "tsYellow",
74            Self::Cyan => "tsCyan",
75            Self::Magenta => "tsMagenta",
76            Self::Gray => "tsGray",
77            Self::DarkRed => "tsDarkRed",
78            Self::DarkGreen => "tsDarkGreen",
79            Self::DarkBlue => "tsDarkBlue",
80            Self::DarkYellow => "tsDarkYellow",
81            Self::DarkCyan => "tsDarkCyan",
82            Self::DarkMagenta => "tsDarkMagenta",
83            Self::LightGray => "tsLightGray",
84            Self::DarkGray => "tsDarkGray",
85        }
86    }
87
88    /// The value the engine yields for this constant.
89    ///
90    /// Little-endian `0x00BBGGRR`: `Red` is `0x0000FF` and `Blue` is
91    /// `0x00FF0000`. Each value was read back from a live engine.
92    #[must_use]
93    pub const fn value(self) -> u32 {
94        match self {
95            Self::Black => 0x0000_0000,
96            Self::White => 0x00ff_ffff,
97            Self::Red => 0x0000_00ff,
98            Self::Green => 0x0000_ff00,
99            Self::Blue => 0x00ff_0000,
100            Self::Yellow => 0x0000_ffff,
101            Self::Cyan => 0x00ff_ff00,
102            Self::Magenta => 0x00ff_00ff,
103            Self::Gray => 0x00a0_a0a0,
104            Self::DarkRed => 0x0000_0080,
105            Self::DarkGreen => 0x0000_8000,
106            Self::DarkBlue => 0x0080_0000,
107            Self::DarkYellow => 0x0000_8080,
108            Self::DarkCyan => 0x0080_8000,
109            Self::DarkMagenta => 0x0080_0080,
110            Self::LightGray => 0x00c0_c0c0,
111            Self::DarkGray => 0x0080_8080,
112        }
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::ColorConstant;
119
120    #[test]
121    fn every_name_is_distinct() {
122        let mut names: Vec<&str> = ColorConstant::ALL.iter().map(|item| item.name()).collect();
123        names.sort_unstable();
124        let count = names.len();
125        names.dedup();
126        assert_eq!(names.len(), count);
127    }
128
129    #[test]
130    fn the_byte_order_is_little_endian() {
131        // Measured: red occupies the low byte and blue the high one, which is
132        // the opposite of the RRGGBB order most tools write.
133        assert_eq!(ColorConstant::Red.value(), 0x0000_00ff);
134        assert_eq!(ColorConstant::Green.value(), 0x0000_ff00);
135        assert_eq!(ColorConstant::Blue.value(), 0x00ff_0000);
136    }
137
138    #[test]
139    fn every_name_carries_the_engine_prefix() {
140        assert!(
141            ColorConstant::ALL
142                .iter()
143                .all(|c| c.name().starts_with("ts"))
144        );
145    }
146}