1//! Global override of color control
2
3#![cfg_attr(not(test), no_std)]
4
5use core::sync::atomic::{AtomicUsize, Ordering};
6
7/// Selection for overriding color output
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9pub enum ColorChoice {
10 Auto,
11 AlwaysAnsi,
12 Always,
13 Never,
14}
15
16impl 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
28impl Default for ColorChoice {
29 fn default() -> Self {
30 Self::Auto
31 }
32}
33
34static USER: AtomicChoice = AtomicChoice::new();
35
36#[derive(Debug)]
37pub(crate) struct AtomicChoice(AtomicUsize);
38
39impl 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
76impl Default for AtomicChoice {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82#[cfg(test)]
83mod 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