verbosity/verbosity.rs
1//! Global verbosity level, used for reporting
2
3use std::fmt;
4use std::fmt::Display;
5use std::fmt::Formatter;
6use std::str::FromStr;
7use std::sync::atomic::AtomicBool;
8use std::sync::atomic::Ordering;
9use std::sync::Arc;
10
11use lazy_static::lazy_static;
12use parking_lot::RwLock;
13
14/// Verbosity level option <`Verbose`|`Terse`|`Quite`>
15#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
16pub enum Verbosity {
17 /// No output option
18 Quite = 0,
19 /// Minimal reporting option
20 Terse = 1,
21 /// Extended reporting option
22 Verbose = 2,
23}
24
25impl Display for Verbosity {
26 fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
27 match self {
28 Self::Terse => fmt.write_str("terse"),
29 Self::Verbose => fmt.write_str("verbose"),
30 Self::Quite => fmt.write_str("quite"),
31 }
32 }
33}
34
35impl FromStr for Verbosity {
36 type Err = String;
37
38 fn from_str(source: &str) -> Result<Self, Self::Err> {
39 match source {
40 "terse" => Ok(Self::Terse),
41 "verbose" => Ok(Self::Verbose),
42 "quite" => Ok(Self::Quite),
43 _ => Err(format!("{:?} is not a valid verbosity", source)),
44 }
45 }
46}
47
48lazy_static! {
49 static ref REPORTING: Arc<RwLock<Verbosity>> = Arc::new(RwLock::new(Verbosity::Quite));
50 static ref REPORTING_SET: AtomicBool = AtomicBool::new(false);
51}
52
53impl Verbosity {
54 /// Gets the global [`Verbosity`] level
55 ///
56 /// ```rust
57 /// # use verbosity::Verbosity;
58 /// Verbosity::Verbose.set_as_global();
59 ///
60 /// assert_eq!(Verbosity::level(), Verbosity::Verbose);
61 /// ```
62 ///
63 /// [`Verbosity`]: Verbosity
64 #[must_use]
65 #[inline]
66 pub fn level() -> Self {
67 *REPORTING.read()
68 }
69
70 /// Checks if global [`Verbosity`] level is `Quite`
71 ///
72 /// ```rust
73 /// # use verbosity::Verbosity;
74 /// Verbosity::Quite.set_as_global();
75 ///
76 /// assert_eq!(Verbosity::level(), Verbosity::Quite);
77 /// ```
78 ///
79 /// [`Verbosity`]: Verbosity
80 #[must_use]
81 #[inline]
82 pub fn is_quite() -> bool {
83 *REPORTING.read() == Self::Quite
84 }
85
86 /// Checks if global [`Verbosity`] level is `Terse`
87 ///
88 /// * is not terse if level is 'Quite'
89 ///
90 /// ```rust
91 /// # use verbosity::Verbosity;
92 /// Verbosity::Quite.set_as_global();
93 ///
94 /// assert_eq!(Verbosity::level(), Verbosity::Quite);
95 /// assert!(!Verbosity::is_terse())
96 /// ```
97 ///
98 /// * is terse if level is `Terse`
99 ///
100 /// ```rust
101 /// # use verbosity::Verbosity;
102 /// Verbosity::Terse.set_as_global();
103 ///
104 /// assert_eq!(Verbosity::level(), Verbosity::Terse);
105 /// assert!(Verbosity::is_terse())
106 /// ```
107 ///
108 /// * is terse also if level is 'Verbose'
109 ///
110 /// ```rust
111 /// # use verbosity::Verbosity;
112 /// Verbosity::Verbose.set_as_global();
113 ///
114 /// assert_eq!(Verbosity::level(), Verbosity::Verbose);
115 /// assert!(Verbosity::is_terse())
116 /// ```
117 ///
118 /// [`Verbosity`]: Verbosity
119 #[must_use]
120 #[inline]
121 pub fn is_terse() -> bool {
122 *REPORTING.read() != Self::Quite
123 }
124
125 /// Checks if global [`Verbosity`] level is 'Verbose'
126 ///
127 /// * is not verbose if level is 'Quite'
128 ///
129 /// ```rust
130 /// # use verbosity::Verbosity;
131 /// Verbosity::Quite.set_as_global();
132 ///
133 /// assert_eq!(Verbosity::level(), Verbosity::Quite);
134 /// assert!(!Verbosity::is_verbose())
135 /// ```
136 ///
137 /// * is not verbose if level is `Terse`
138 ///
139 /// ```rust
140 /// # use verbosity::Verbosity;
141 /// Verbosity::Terse.set_as_global();
142 ///
143 /// assert_eq!(Verbosity::level(), Verbosity::Terse);
144 /// assert!(!Verbosity::is_verbose())
145 /// ```
146 ///
147 /// * is verbose if level is 'Verbose'
148 ///
149 /// ```rust
150 /// # use verbosity::Verbosity;
151 /// Verbosity::Verbose.set_as_global();
152 ///
153 /// assert_eq!(Verbosity::level(), Verbosity::Verbose);
154 /// assert!(Verbosity::is_verbose())
155 /// ```
156 ///
157 /// [`Verbosity`]: Verbosity
158 #[must_use]
159 #[inline]
160 pub fn is_verbose() -> bool {
161 *REPORTING.read() == Self::Verbose
162 }
163
164 /// Sets the instance of a [`Verbosity`] level as the global level
165 ///
166 /// ```rust
167 /// # use verbosity::Verbosity;
168 /// Verbosity::Verbose.set_as_global();
169 ///
170 /// assert_eq!(Verbosity::level(), Verbosity::Verbose);
171 ///
172 /// Verbosity::Quite.set_as_global();
173 ///
174 /// assert_ne!(Verbosity::level(), Verbosity::Quite);
175 /// assert_eq!(Verbosity::level(), Verbosity::Verbose);
176 /// ```
177 ///
178 /// \* _this can only be set once, all other calls will be ignored_
179 ///
180 /// [`Verbosity`]: Verbosity
181 pub fn set_as_global(self) {
182 let set =
183 match REPORTING_SET.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) {
184 Ok(set) | Err(set) => set,
185 };
186
187 if !set {
188 *REPORTING.write() = self;
189 }
190 }
191
192 /// only for testing
193 #[cfg(test)]
194 #[doc(hidden)]
195 pub fn set_as_global_for_test(self) {
196 *REPORTING.write() = self;
197 }
198}