1use std::{fmt, str::FromStr};
2
3use crate::Error;
4
5pub(crate) const LOG_LEVEL_NAMES: [&str; Level::count()] =
6 ["critical", "error", "warn", "info", "debug", "trace"];
7
8const LOG_LEVEL_SHORT_NAMES: [&str; Level::count()] = ["C", "E", "W", "I", "D", "T"];
9
10#[repr(u16)]
52#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
53pub enum Level {
54 Critical = 0,
56 Error,
58 Warn,
60 Info,
62 Debug,
64 Trace,
66}
67
68#[cfg(feature = "serde")]
69impl serde::Serialize for Level {
70 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71 where
72 S: serde::Serializer,
73 {
74 serializer.serialize_str(self.as_str())
75 }
76}
77
78impl Level {
79 #[must_use]
80 fn from_usize(u: usize) -> Option<Level> {
81 match u {
82 0 => Some(Level::Critical),
83 1 => Some(Level::Error),
84 2 => Some(Level::Warn),
85 3 => Some(Level::Info),
86 4 => Some(Level::Debug),
87 5 => Some(Level::Trace),
88 _ => None,
89 }
90 }
91
92 #[must_use]
93 const fn min_usize() -> usize {
94 Self::most_severe() as usize
95 }
96
97 #[must_use]
98 const fn max_usize() -> usize {
99 Self::most_verbose() as usize
100 }
101
102 #[must_use]
103 pub(crate) const fn count() -> usize {
104 Self::max_usize() + 1
105 }
106
107 #[must_use]
109 pub const fn most_severe() -> Level {
110 Level::Critical
111 }
112
113 #[must_use]
115 pub const fn most_verbose() -> Level {
116 Level::Trace
117 }
118
119 #[must_use]
123 pub fn as_str(&self) -> &'static str {
124 LOG_LEVEL_NAMES[*self as usize]
125 }
126
127 #[must_use]
128 pub(crate) fn as_short_str(&self) -> &'static str {
129 LOG_LEVEL_SHORT_NAMES[*self as usize]
130 }
131
132 pub fn iter() -> impl Iterator<Item = Self> {
147 (Self::min_usize()..=Self::max_usize()).map(|i| Self::from_usize(i).unwrap())
148 }
149}
150
151#[cfg(feature = "log")]
152impl From<log::Level> for Level {
153 fn from(level: log::Level) -> Self {
154 match level {
155 log::Level::Error => Self::Error,
156 log::Level::Warn => Self::Warn,
157 log::Level::Info => Self::Info,
158 log::Level::Debug => Self::Debug,
159 log::Level::Trace => Self::Trace,
160 }
161 }
162}
163
164impl fmt::Display for Level {
165 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166 f.write_str(self.as_str())
167 }
168}
169
170impl FromStr for Level {
171 type Err = Error;
172
173 fn from_str(level: &str) -> Result<Level, Self::Err> {
174 LOG_LEVEL_NAMES
175 .iter()
176 .position(|&name| name.eq_ignore_ascii_case(level))
177 .into_iter()
178 .map(|idx| Level::from_usize(idx).unwrap())
179 .next()
180 .ok_or_else(|| Error::ParseLevel(level.to_string()))
181 }
182}
183
184#[repr(align(4))]
189#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
190pub enum LevelFilter {
191 Off,
193 Equal(Level),
195 NotEqual(Level),
197 MoreSevere(Level),
199 MoreSevereEqual(Level),
202 MoreVerbose(Level),
204 MoreVerboseEqual(Level),
207 All,
209}
210
211impl LevelFilter {
212 #[deprecated(
214 since = "0.4.0",
215 note = "it may be removed in the future, use method `test()` instead"
216 )]
217 #[must_use]
218 pub fn compare(&self, level: Level) -> bool {
219 self.__test_const(level)
220 }
221
222 #[must_use]
237 pub fn test(&self, level: Level) -> bool {
238 self.__test_const(level)
239 }
240
241 #[doc(hidden)]
243 #[must_use]
244 pub const fn __test_const(&self, level: Level) -> bool {
245 let level_num: u16 = level as u16;
246
247 match *self {
248 Self::Off => false,
249 Self::Equal(stored) => level_num == stored as u16,
250 Self::NotEqual(stored) => level_num != stored as u16,
251 Self::MoreSevere(stored) => level_num < stored as u16,
252 Self::MoreSevereEqual(stored) => level_num <= stored as u16,
253 Self::MoreVerbose(stored) => level_num > stored as u16,
254 Self::MoreVerboseEqual(stored) => level_num >= stored as u16,
255 Self::All => true,
256 }
257 }
258
259 #[must_use]
260 pub(crate) fn from_str_for_env(text: &str) -> Option<LevelFilter> {
261 if let Ok(level) = Level::from_str(text) {
262 Some(LevelFilter::MoreSevereEqual(level))
263 } else if text.eq_ignore_ascii_case("off") {
264 Some(LevelFilter::Off)
265 } else if text.eq_ignore_ascii_case("all") {
266 Some(LevelFilter::All)
267 } else {
268 None
269 }
270 }
271}
272
273#[cfg(feature = "log")]
274impl From<log::LevelFilter> for LevelFilter {
275 fn from(filter: log::LevelFilter) -> Self {
276 match filter {
277 log::LevelFilter::Off => Self::Off,
278 filter => Self::MoreSevereEqual(Level::from(filter.to_level().unwrap())),
279 }
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use std::mem::{align_of, size_of};
286
287 use super::*;
288 use crate::utils::const_assert;
289
290 const_assert!(atomic::Atomic::<Level>::is_lock_free());
291 const_assert!(atomic::Atomic::<LevelFilter>::is_lock_free());
292 const_assert!(size_of::<Level>() * 2 == size_of::<LevelFilter>());
293 const_assert!(align_of::<Level>() * 2 == align_of::<LevelFilter>());
294
295 #[test]
296 fn from_usize() {
297 assert_eq!(
298 Level::most_severe(),
299 Level::from_usize(Level::min_usize()).unwrap()
300 );
301
302 assert_eq!(
303 Level::most_verbose(),
304 Level::from_usize(Level::max_usize()).unwrap()
305 );
306 }
307
308 #[test]
309 fn from_str() {
310 fn to_random_case(input: &str) -> String {
311 input
312 .char_indices()
313 .map(|(i, char)| {
314 if i % 2 != 0 {
315 char.to_ascii_uppercase()
316 } else {
317 char.to_ascii_lowercase()
318 }
319 })
320 .collect::<String>()
321 }
322
323 for (i, &name) in LOG_LEVEL_NAMES.iter().enumerate() {
324 let from_usize = Level::from_usize(i);
325 let from_str = (
326 Level::from_str(&name.to_lowercase()),
327 Level::from_str(&name.to_uppercase()),
328 Level::from_str(&to_random_case(name)),
329 );
330
331 assert_eq!(from_usize.unwrap(), from_str.0.unwrap());
332 assert_eq!(from_usize.unwrap(), from_str.1.unwrap());
333 assert_eq!(from_usize.unwrap(), from_str.2.unwrap());
334 }
335
336 assert!(Level::from_str("notexist").is_err());
337 }
338
339 #[test]
340 fn as_short_str() {
341 for (&name, &short_name) in LOG_LEVEL_NAMES.iter().zip(LOG_LEVEL_SHORT_NAMES.iter()) {
342 assert_eq!(
343 name.chars()
344 .next()
345 .unwrap()
346 .to_ascii_uppercase()
347 .to_string(),
348 short_name
349 );
350 }
351 }
352
353 #[test]
354 fn level_filter_from_str_for_env() {
355 assert_eq!(
356 LevelFilter::MoreSevereEqual(Level::Info),
357 LevelFilter::from_str_for_env("iNFo").unwrap()
358 );
359
360 assert_eq!(
361 LevelFilter::MoreSevereEqual(Level::Warn),
362 LevelFilter::from_str_for_env("wARn").unwrap()
363 );
364
365 assert_eq!(
366 LevelFilter::Off,
367 LevelFilter::from_str_for_env("oFf").unwrap()
368 );
369
370 assert_eq!(
371 LevelFilter::All,
372 LevelFilter::from_str_for_env("aLl").unwrap()
373 );
374 }
375
376 #[test]
377 fn iter() {
378 let mut iter = Level::iter();
379 assert_eq!(iter.next(), Some(Level::Critical));
380 assert_eq!(iter.next(), Some(Level::Error));
381 assert_eq!(iter.next(), Some(Level::Warn));
382 assert_eq!(iter.next(), Some(Level::Info));
383 assert_eq!(iter.next(), Some(Level::Debug));
384 assert_eq!(iter.next(), Some(Level::Trace));
385 assert_eq!(iter.next(), None);
386 }
387
388 #[test]
389 fn filter() {
390 assert!(!LevelFilter::Off.test(Level::Trace));
391 assert!(!LevelFilter::Off.test(Level::Critical));
392 assert!(!LevelFilter::Off.test(Level::Warn));
393
394 assert!(LevelFilter::Equal(Level::Error).test(Level::Error));
395 assert!(!LevelFilter::Equal(Level::Error).test(Level::Warn));
396 assert!(!LevelFilter::Equal(Level::Error).test(Level::Critical));
397
398 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Trace));
399 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Info));
400 assert!(!LevelFilter::NotEqual(Level::Error).test(Level::Error));
401
402 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Warn));
403 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Error));
404 assert!(!LevelFilter::MoreSevere(Level::Info).test(Level::Info));
405
406 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Warn));
407 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Info));
408 assert!(!LevelFilter::MoreSevereEqual(Level::Info).test(Level::Trace));
409
410 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Warn));
411 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Info));
412 assert!(!LevelFilter::MoreVerbose(Level::Error).test(Level::Error));
413
414 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Warn));
415 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Error));
416 assert!(!LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Critical));
417
418 assert!(LevelFilter::All.test(Level::Trace));
419 assert!(LevelFilter::All.test(Level::Critical));
420 assert!(LevelFilter::All.test(Level::Error));
421 }
422
423 #[cfg(feature = "log")]
424 #[test]
425 fn filter_from_log() {
426 assert_eq!(LevelFilter::from(log::LevelFilter::Off), LevelFilter::Off);
427 assert_eq!(
428 LevelFilter::from(log::LevelFilter::Error),
429 LevelFilter::MoreSevereEqual(Level::Error)
430 );
431 assert_eq!(
432 LevelFilter::from(log::LevelFilter::Warn),
433 LevelFilter::MoreSevereEqual(Level::Warn)
434 );
435 assert_eq!(
436 LevelFilter::from(log::LevelFilter::Info),
437 LevelFilter::MoreSevereEqual(Level::Info)
438 );
439 assert_eq!(
440 LevelFilter::from(log::LevelFilter::Debug),
441 LevelFilter::MoreSevereEqual(Level::Debug)
442 );
443 assert_eq!(
444 LevelFilter::from(log::LevelFilter::Trace),
445 LevelFilter::MoreSevereEqual(Level::Trace)
446 );
447 }
448}