rocket/config/
cli_colors.rs

1use std::fmt;
2
3use serde::{de, Deserialize, Serialize};
4
5/// Enable or disable coloring when logging.
6///
7/// Valid configuration values are:
8///
9///   * `"always"` - [`CliColors::Always`]
10///   * `"auto"`, `1`, or `true` - [`CliColors::Auto`] _(default)_
11///   * `"never"`, `0`, or `false` - [`CliColors::Never`]
12#[derive(Debug, Copy, Clone, Default, Serialize, PartialEq, Eq, Hash)]
13pub enum CliColors {
14    /// Always enable colors, irrespective of `stdout` and `stderr`.
15    ///
16    /// Case-insensitive string values of `"always"` parse as this value.
17    Always,
18
19    /// Enable colors _only if_ `stdout` and `stderr` support coloring.
20    ///
21    /// Case-insensitive string values of `"auto"`, the boolean `true`, and the
22    /// integer `1` all parse as this value.
23    ///
24    /// Only Unix-like systems (Linux, macOS, BSD, etc.), this is equivalent to
25    /// checking if `stdout` and `stderr` are both TTYs. On Windows, the console
26    /// is queried for ANSI escape sequence based coloring support and enabled
27    /// if support is successfully enabled.
28    #[default]
29    Auto,
30
31    /// Never enable colors, even if `stdout` and `stderr` support them.
32    ///
33    /// Case-insensitive string values of `"never"`, the boolean `false`, and
34    /// the integer `0` all parse as this value.
35    Never,
36}
37
38impl fmt::Display for CliColors {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            CliColors::Always => write!(f, "always"),
42            CliColors::Auto => write!(f, "auto"),
43            CliColors::Never => write!(f, "never")
44        }
45    }
46}
47
48impl<'de> Deserialize<'de> for CliColors {
49    fn deserialize<D: de::Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
50        struct Visitor;
51
52        impl<'de> de::Visitor<'de> for Visitor {
53            type Value = CliColors;
54
55            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56                f.write_str("0, 1, false, true, always, auto, or never")
57            }
58
59            fn visit_str<E: de::Error>(self, val: &str) -> Result<CliColors, E> {
60                match val.to_lowercase().as_str() {
61                    "true" => Ok(CliColors::Auto),
62                    "false" => Ok(CliColors::Never),
63                    "1" => Ok(CliColors::Auto),
64                    "0" => Ok(CliColors::Never),
65                    "always" => Ok(CliColors::Always),
66                    "auto" => Ok(CliColors::Auto),
67                    "never" => Ok(CliColors::Never),
68                    _ => Err(E::invalid_value(de::Unexpected::Str(val), &self)),
69                }
70            }
71
72            fn visit_bool<E: de::Error>(self, val: bool) -> Result<CliColors, E> {
73                match val {
74                    true => Ok(CliColors::Auto),
75                    false => Ok(CliColors::Never),
76                }
77            }
78
79            fn visit_i64<E: de::Error>(self, val: i64) -> Result<CliColors, E> {
80                match val {
81                    1 => Ok(CliColors::Auto),
82                    0 => Ok(CliColors::Never),
83                    _ => Err(E::invalid_value(de::Unexpected::Signed(val), &self)),
84                }
85            }
86
87            fn visit_u64<E: de::Error>(self, val: u64) -> Result<CliColors, E> {
88                match val {
89                    1 => Ok(CliColors::Auto),
90                    0 => Ok(CliColors::Never),
91                    _ => Err(E::invalid_value(de::Unexpected::Unsigned(val), &self)),
92                }
93            }
94        }
95
96        de.deserialize_any(Visitor)
97    }
98}