1 | //! Global override of color control |
2 | |
3 | #![cfg_attr (not(test), no_std)] |
4 | |
5 | use core::sync::atomic::{AtomicUsize, Ordering}; |
6 | |
7 | /// Selection for overriding color output |
8 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
9 | pub enum ColorChoice { |
10 | Auto, |
11 | AlwaysAnsi, |
12 | Always, |
13 | Never, |
14 | } |
15 | |
16 | impl ColorChoice { |
17 | /// Get the current [`ColorChoice`] state |
18 | pub fn global() -> Self { |
19 | USER.get() |
20 | } |
21 | |
22 | /// Override the detected [`ColorChoice`] |
23 | pub fn write_global(self) { |
24 | USER.set(self) |
25 | } |
26 | } |
27 | |
28 | impl Default for ColorChoice { |
29 | fn default() -> Self { |
30 | Self::Auto |
31 | } |
32 | } |
33 | |
34 | static USER: AtomicChoice = AtomicChoice::new(); |
35 | |
36 | #[derive (Debug)] |
37 | pub(crate) struct AtomicChoice(AtomicUsize); |
38 | |
39 | impl AtomicChoice { |
40 | pub(crate) const fn new() -> Self { |
41 | Self(AtomicUsize::new(Self::from_choice( |
42 | crate::ColorChoice::Auto, |
43 | ))) |
44 | } |
45 | |
46 | pub(crate) fn get(&self) -> crate::ColorChoice { |
47 | let choice = self.0.load(Ordering::SeqCst); |
48 | Self::to_choice(choice).unwrap() |
49 | } |
50 | |
51 | pub(crate) fn set(&self, choice: crate::ColorChoice) { |
52 | let choice = Self::from_choice(choice); |
53 | self.0.store(choice, Ordering::SeqCst); |
54 | } |
55 | |
56 | const fn from_choice(choice: crate::ColorChoice) -> usize { |
57 | match choice { |
58 | crate::ColorChoice::Auto => 0, |
59 | crate::ColorChoice::AlwaysAnsi => 1, |
60 | crate::ColorChoice::Always => 2, |
61 | crate::ColorChoice::Never => 3, |
62 | } |
63 | } |
64 | |
65 | const fn to_choice(choice: usize) -> Option<crate::ColorChoice> { |
66 | match choice { |
67 | 0 => Some(crate::ColorChoice::Auto), |
68 | 1 => Some(crate::ColorChoice::AlwaysAnsi), |
69 | 2 => Some(crate::ColorChoice::Always), |
70 | 3 => Some(crate::ColorChoice::Never), |
71 | _ => None, |
72 | } |
73 | } |
74 | } |
75 | |
76 | impl Default for AtomicChoice { |
77 | fn default() -> Self { |
78 | Self::new() |
79 | } |
80 | } |
81 | |
82 | #[cfg (test)] |
83 | mod test { |
84 | use super::*; |
85 | |
86 | #[test ] |
87 | fn choice_serialization() { |
88 | let expected = vec![ |
89 | ColorChoice::Auto, |
90 | ColorChoice::AlwaysAnsi, |
91 | ColorChoice::Always, |
92 | ColorChoice::Never, |
93 | ]; |
94 | let values: Vec<_> = expected |
95 | .iter() |
96 | .cloned() |
97 | .map(AtomicChoice::from_choice) |
98 | .collect(); |
99 | let actual: Vec<_> = values |
100 | .iter() |
101 | .cloned() |
102 | .filter_map(AtomicChoice::to_choice) |
103 | .collect(); |
104 | assert_eq!(expected, actual); |
105 | } |
106 | } |
107 | |