owo_colors/colors/
custom.rs

1use crate::Color;
2
3const U8_TO_STR: [[u8; 3]; 256] = generate_lookup();
4
5const fn generate_lookup() -> [[u8; 3]; 256] {
6    let mut table = [[0, 0, 0]; 256];
7
8    let mut i = 0;
9    while i < 256 {
10        table[i] = [
11            b'0' + (i / 100) as u8,
12            b'0' + (i / 10 % 10) as u8,
13            b'0' + (i % 10) as u8,
14        ];
15        i += 1;
16    }
17
18    table
19}
20
21const fn rgb_to_ansi(r: u8, g: u8, b: u8, is_fg: bool) -> [u8; 19] {
22    let mut buf = if is_fg {
23        *b"\x1b[38;2;rrr;ggg;bbbm"
24    } else {
25        *b"\x1b[48;2;rrr;ggg;bbbm"
26    };
27
28    let r = U8_TO_STR[r as usize];
29    let g = U8_TO_STR[g as usize];
30    let b = U8_TO_STR[b as usize];
31
32    // r 7
33    buf[7] = r[0];
34    buf[8] = r[1];
35    buf[9] = r[2];
36
37    // g 11
38    buf[11] = g[0];
39    buf[12] = g[1];
40    buf[13] = g[2];
41
42    // b 15
43    buf[15] = b[0];
44    buf[16] = b[1];
45    buf[17] = b[2];
46
47    buf
48}
49
50const fn rgb_to_ansi_color(r: u8, g: u8, b: u8, is_fg: bool) -> [u8; 16] {
51    let mut buf = if is_fg {
52        *b"38;2;rrr;ggg;bbb"
53    } else {
54        *b"48;2;rrr;ggg;bbb"
55    };
56
57    let r = U8_TO_STR[r as usize];
58    let g = U8_TO_STR[g as usize];
59    let b = U8_TO_STR[b as usize];
60
61    // r 5
62    buf[5] = r[0];
63    buf[6] = r[1];
64    buf[7] = r[2];
65
66    // g 9
67    buf[9] = g[0];
68    buf[10] = g[1];
69    buf[11] = g[2];
70
71    // b 13
72    buf[13] = b[0];
73    buf[14] = b[1];
74    buf[15] = b[2];
75
76    buf
77}
78
79/// A custom RGB color, determined at compile time
80pub struct CustomColor<const R: u8, const G: u8, const B: u8>;
81
82/// This exists since unwrap() isn't const-safe (it invokes formatting infrastructure)
83const fn bytes_to_str(bytes: &'static [u8]) -> &'static str {
84    match core::str::from_utf8(bytes) {
85        Ok(o) => o,
86        Err(_e) => panic!("Const parsing &[u8] to a string failed!"),
87    }
88}
89
90impl<const R: u8, const G: u8, const B: u8> CustomColor<R, G, B> {
91    const ANSI_FG_U8: [u8; 19] = rgb_to_ansi(R, G, B, true);
92    const ANSI_BG_U8: [u8; 19] = rgb_to_ansi(R, G, B, true);
93    const RAW_ANSI_FG_U8: [u8; 16] = rgb_to_ansi_color(R, G, B, true);
94    const RAW_ANSI_BG_U8: [u8; 16] = rgb_to_ansi_color(R, G, B, true);
95}
96
97impl<const R: u8, const G: u8, const B: u8> crate::private::Sealed for CustomColor<R, G, B> {}
98
99impl<const R: u8, const G: u8, const B: u8> Color for CustomColor<R, G, B> {
100    const ANSI_FG: &'static str = bytes_to_str(&Self::ANSI_FG_U8);
101    const ANSI_BG: &'static str = bytes_to_str(&Self::ANSI_BG_U8);
102    const RAW_ANSI_FG: &'static str = bytes_to_str(&Self::RAW_ANSI_FG_U8);
103    const RAW_ANSI_BG: &'static str = bytes_to_str(&Self::RAW_ANSI_BG_U8);
104
105    #[doc(hidden)]
106    type DynEquivalent = crate::Rgb;
107
108    #[doc(hidden)]
109    const DYN_EQUIVALENT: Self::DynEquivalent = crate::Rgb(R, G, B);
110
111    #[doc(hidden)]
112    const DYN_COLORS_EQUIVALENT: crate::DynColors = crate::DynColors::Rgb(R, G, B);
113}