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}