1#![cfg_attr(not(test), no_std)]
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5#![warn(missing_docs)]
6#![warn(clippy::print_stderr)]
7#![warn(clippy::print_stdout)]
8
9use core::sync::atomic::{AtomicUsize, Ordering};
10
11#[allow(clippy::exhaustive_enums)]
13#[derive(Copy, Clone, Debug, PartialEq, Eq)]
14pub enum ColorChoice {
15 Auto,
17 AlwaysAnsi,
20 Always,
24 Never,
26}
27
28impl ColorChoice {
29 pub fn global() -> Self {
31 USER.get()
32 }
33
34 pub fn write_global(self) {
36 USER.set(self);
37 }
38}
39
40impl Default for ColorChoice {
41 fn default() -> Self {
42 Self::Auto
43 }
44}
45
46static USER: AtomicChoice = AtomicChoice::new();
47
48#[derive(Debug)]
49pub(crate) struct AtomicChoice(AtomicUsize);
50
51impl AtomicChoice {
52 pub(crate) const fn new() -> Self {
53 Self(AtomicUsize::new(Self::from_choice(ColorChoice::Auto)))
54 }
55
56 pub(crate) fn get(&self) -> ColorChoice {
57 let choice = self.0.load(Ordering::SeqCst);
58 Self::to_choice(choice).expect("Only `ColorChoice` values can be `set`")
59 }
60
61 pub(crate) fn set(&self, choice: ColorChoice) {
62 let choice = Self::from_choice(choice);
63 self.0.store(choice, Ordering::SeqCst);
64 }
65
66 const fn from_choice(choice: ColorChoice) -> usize {
67 match choice {
68 ColorChoice::Auto => 0,
69 ColorChoice::AlwaysAnsi => 1,
70 ColorChoice::Always => 2,
71 ColorChoice::Never => 3,
72 }
73 }
74
75 const fn to_choice(choice: usize) -> Option<ColorChoice> {
76 match choice {
77 0 => Some(ColorChoice::Auto),
78 1 => Some(ColorChoice::AlwaysAnsi),
79 2 => Some(ColorChoice::Always),
80 3 => Some(ColorChoice::Never),
81 _ => None,
82 }
83 }
84}
85
86impl Default for AtomicChoice {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92#[cfg(test)]
93mod test {
94 use super::*;
95
96 #[test]
97 fn choice_serialization() {
98 let expected = vec![
99 ColorChoice::Auto,
100 ColorChoice::AlwaysAnsi,
101 ColorChoice::Always,
102 ColorChoice::Never,
103 ];
104 let values: Vec<_> = expected
105 .iter()
106 .cloned()
107 .map(AtomicChoice::from_choice)
108 .collect();
109 let actual: Vec<_> = values
110 .iter()
111 .cloned()
112 .filter_map(AtomicChoice::to_choice)
113 .collect();
114 assert_eq!(expected, actual);
115 }
116}