1use std::{
2 fmt::{self, Debug},
3 str::FromStr,
4 sync::atomic::Ordering,
5};
6
7use crate::Error;
8
9pub(crate) const LOG_LEVEL_NAMES: [&str; Level::count()] =
10 ["critical", "error", "warn", "info", "debug", "trace"];
11
12const LOG_LEVEL_SHORT_NAMES: [&str; Level::count()] = ["C", "E", "W", "I", "D", "T"];
13
14#[repr(u16)]
56#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, bytemuck::NoUninit)]
57pub enum Level {
58 Critical = 0,
60 Error,
62 Warn,
64 Info,
66 Debug,
68 Trace,
70}
71
72#[cfg(feature = "serde")]
73impl serde::Serialize for Level {
74 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75 where
76 S: serde::Serializer,
77 {
78 serializer.serialize_str(self.as_str())
79 }
80}
81
82impl Level {
83 #[must_use]
84 fn from_usize(u: usize) -> Option<Level> {
85 match u {
86 0 => Some(Level::Critical),
87 1 => Some(Level::Error),
88 2 => Some(Level::Warn),
89 3 => Some(Level::Info),
90 4 => Some(Level::Debug),
91 5 => Some(Level::Trace),
92 _ => None,
93 }
94 }
95
96 #[must_use]
97 const fn min_usize() -> usize {
98 Self::most_severe() as usize
99 }
100
101 #[must_use]
102 const fn max_usize() -> usize {
103 Self::most_verbose() as usize
104 }
105
106 #[must_use]
108 pub const fn count() -> usize {
109 Self::max_usize() + 1
110 }
111
112 #[must_use]
114 pub const fn most_severe() -> Level {
115 Level::Critical
116 }
117
118 #[must_use]
120 pub const fn most_verbose() -> Level {
121 Level::Trace
122 }
123
124 #[must_use]
128 pub fn as_str(&self) -> &'static str {
129 LOG_LEVEL_NAMES[*self as usize]
130 }
131
132 #[must_use]
133 pub(crate) fn as_short_str(&self) -> &'static str {
134 LOG_LEVEL_SHORT_NAMES[*self as usize]
135 }
136
137 pub fn iter() -> impl Iterator<Item = Self> {
152 (Self::min_usize()..=Self::max_usize()).map(|i| Self::from_usize(i).unwrap())
153 }
154}
155
156#[cfg(feature = "log")]
157impl From<log::Level> for Level {
158 fn from(level: log::Level) -> Self {
159 match level {
160 log::Level::Error => Self::Error,
161 log::Level::Warn => Self::Warn,
162 log::Level::Info => Self::Info,
163 log::Level::Debug => Self::Debug,
164 log::Level::Trace => Self::Trace,
165 }
166 }
167}
168
169impl fmt::Display for Level {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 f.write_str(self.as_str())
172 }
173}
174
175impl FromStr for Level {
176 type Err = Error;
177
178 fn from_str(level: &str) -> Result<Level, Self::Err> {
179 LOG_LEVEL_NAMES
180 .iter()
181 .position(|&name| name.eq_ignore_ascii_case(level))
182 .into_iter()
183 .map(|idx| Level::from_usize(idx).unwrap())
184 .next()
185 .ok_or_else(|| Error::ParseLevel(level.to_string()))
186 }
187}
188
189#[repr(u16)]
190#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, bytemuck::NoUninit)]
191enum LevelFilterDiscriminant {
192 Off,
193 Equal,
194 NotEqual,
195 MoreSevere,
196 MoreSevereEqual,
197 MoreVerbose,
198 MoreVerboseEqual,
199 All,
200}
201
202#[repr(align(4))]
207#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
208pub enum LevelFilter {
209 Off,
211 Equal(Level),
213 NotEqual(Level),
215 MoreSevere(Level),
217 MoreSevereEqual(Level),
220 MoreVerbose(Level),
222 MoreVerboseEqual(Level),
225 All,
227}
228
229impl LevelFilter {
230 #[deprecated(
232 since = "0.4.0",
233 note = "it may be removed in the future, use method `test()` instead"
234 )]
235 #[must_use]
236 pub fn compare(&self, level: Level) -> bool {
237 self.__test_const(level)
238 }
239
240 #[must_use]
255 pub fn test(&self, level: Level) -> bool {
256 self.__test_const(level)
257 }
258
259 #[doc(hidden)]
261 #[must_use]
262 pub const fn __test_const(&self, level: Level) -> bool {
263 let level_num: u16 = level as u16;
264
265 match *self {
266 Self::Off => false,
267 Self::Equal(stored) => level_num == stored as u16,
268 Self::NotEqual(stored) => level_num != stored as u16,
269 Self::MoreSevere(stored) => level_num < stored as u16,
270 Self::MoreSevereEqual(stored) => level_num <= stored as u16,
271 Self::MoreVerbose(stored) => level_num > stored as u16,
272 Self::MoreVerboseEqual(stored) => level_num >= stored as u16,
273 Self::All => true,
274 }
275 }
276
277 #[must_use]
278 pub(crate) fn from_str_for_env(text: &str) -> Option<LevelFilter> {
279 if let Ok(level) = Level::from_str(text) {
280 Some(LevelFilter::MoreSevereEqual(level))
281 } else if text.eq_ignore_ascii_case("off") {
282 Some(LevelFilter::Off)
283 } else if text.eq_ignore_ascii_case("all") {
284 Some(LevelFilter::All)
285 } else {
286 None
287 }
288 }
289
290 #[must_use]
291 fn discriminant(&self) -> LevelFilterDiscriminant {
292 match self {
293 Self::Off => LevelFilterDiscriminant::Off,
294 Self::Equal(_) => LevelFilterDiscriminant::Equal,
295 Self::NotEqual(_) => LevelFilterDiscriminant::NotEqual,
296 Self::MoreSevere(_) => LevelFilterDiscriminant::MoreSevere,
297 Self::MoreSevereEqual(_) => LevelFilterDiscriminant::MoreSevereEqual,
298 Self::MoreVerbose(_) => LevelFilterDiscriminant::MoreVerbose,
299 Self::MoreVerboseEqual(_) => LevelFilterDiscriminant::MoreVerboseEqual,
300 Self::All => LevelFilterDiscriminant::All,
301 }
302 }
303
304 #[must_use]
305 fn level(&self) -> Option<Level> {
306 match *self {
307 Self::Equal(level)
308 | Self::NotEqual(level)
309 | Self::MoreSevere(level)
310 | Self::MoreSevereEqual(level)
311 | Self::MoreVerbose(level)
312 | Self::MoreVerboseEqual(level) => Some(level),
313 Self::Off | Self::All => None,
314 }
315 }
316}
317
318#[cfg(feature = "log")]
319impl From<log::LevelFilter> for LevelFilter {
320 fn from(filter: log::LevelFilter) -> Self {
321 match filter {
322 log::LevelFilter::Off => Self::Off,
323 filter => Self::MoreSevereEqual(Level::from(filter.to_level().unwrap())),
324 }
325 }
326}
327
328#[repr(C, align(4))]
338#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, bytemuck::NoUninit)]
339struct LevelFilterLayout {
340 discriminant: LevelFilterDiscriminant,
341 level: Level,
342}
343
344impl LevelFilterLayout {
345 const UNDEFINED_FALLBACK: Level = Level::Critical;
346}
347
348impl From<LevelFilter> for LevelFilterLayout {
349 fn from(value: LevelFilter) -> Self {
350 Self {
351 discriminant: value.discriminant(),
352 level: value.level().unwrap_or(Self::UNDEFINED_FALLBACK),
353 }
354 }
355}
356
357impl From<LevelFilterLayout> for LevelFilter {
358 fn from(layout: LevelFilterLayout) -> Self {
359 match layout.discriminant {
360 LevelFilterDiscriminant::Off => Self::Off,
361 LevelFilterDiscriminant::Equal => Self::Equal(layout.level),
362 LevelFilterDiscriminant::NotEqual => Self::NotEqual(layout.level),
363 LevelFilterDiscriminant::MoreSevere => Self::MoreSevere(layout.level),
364 LevelFilterDiscriminant::MoreSevereEqual => Self::MoreSevereEqual(layout.level),
365 LevelFilterDiscriminant::MoreVerbose => Self::MoreVerbose(layout.level),
366 LevelFilterDiscriminant::MoreVerboseEqual => Self::MoreVerboseEqual(layout.level),
367 LevelFilterDiscriminant::All => Self::All,
368 }
369 }
370}
371
372pub struct AtomicLevelFilter {
375 inner: atomic::Atomic<LevelFilterLayout>,
376}
377
378impl AtomicLevelFilter {
379 const ORDERING: Ordering = Ordering::Relaxed;
380
381 #[must_use]
383 pub fn new(init: LevelFilter) -> Self {
384 Self {
385 inner: atomic::Atomic::new(init.into()),
386 }
387 }
388
389 pub fn get(&self) -> LevelFilter {
391 self.load(Self::ORDERING)
392 }
393
394 pub fn set(&self, new: LevelFilter) {
396 self.store(new, Self::ORDERING);
397 }
398
399 pub fn load(&self, ordering: Ordering) -> LevelFilter {
405 self.inner.load(ordering).into()
406 }
407
408 pub fn store(&self, value: LevelFilter, ordering: Ordering) {
414 self.inner.store(value.into(), ordering);
415 }
416
417 pub fn swap(&self, new: LevelFilter, ordering: Ordering) -> LevelFilter {
419 self.inner.swap(new.into(), ordering).into()
420 }
421}
422
423impl Debug for AtomicLevelFilter {
424 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425 self.get().fmt(f)
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use std::mem::size_of;
432
433 use super::*;
434 use crate::utils::const_assert;
435
436 const_assert!(atomic::Atomic::<Level>::is_lock_free());
437 const_assert!(atomic::Atomic::<LevelFilter>::is_lock_free());
438 const_assert!(atomic::Atomic::<LevelFilterLayout>::is_lock_free());
439 const_assert!(size_of::<Level>() * 2 == size_of::<LevelFilter>());
440 const_assert!(align_of::<Level>() * 2 == align_of::<LevelFilter>());
441 const_assert!(size_of::<LevelFilter>() == size_of::<LevelFilterLayout>());
442 const_assert!(align_of::<LevelFilter>() == align_of::<LevelFilterLayout>());
443
444 #[test]
445 fn from_usize() {
446 assert_eq!(
447 Level::most_severe(),
448 Level::from_usize(Level::min_usize()).unwrap()
449 );
450
451 assert_eq!(
452 Level::most_verbose(),
453 Level::from_usize(Level::max_usize()).unwrap()
454 );
455 }
456
457 #[test]
458 fn from_str() {
459 fn to_random_case(input: &str) -> String {
460 input
461 .char_indices()
462 .map(|(i, char)| {
463 if i % 2 != 0 {
464 char.to_ascii_uppercase()
465 } else {
466 char.to_ascii_lowercase()
467 }
468 })
469 .collect::<String>()
470 }
471
472 for (i, &name) in LOG_LEVEL_NAMES.iter().enumerate() {
473 let from_usize = Level::from_usize(i);
474 let from_str = (
475 Level::from_str(&name.to_lowercase()),
476 Level::from_str(&name.to_uppercase()),
477 Level::from_str(&to_random_case(name)),
478 );
479
480 assert_eq!(from_usize.unwrap(), from_str.0.unwrap());
481 assert_eq!(from_usize.unwrap(), from_str.1.unwrap());
482 assert_eq!(from_usize.unwrap(), from_str.2.unwrap());
483 }
484
485 assert!(Level::from_str("notexist").is_err());
486 }
487
488 #[test]
489 fn as_short_str() {
490 for (&name, &short_name) in LOG_LEVEL_NAMES.iter().zip(LOG_LEVEL_SHORT_NAMES.iter()) {
491 assert_eq!(
492 name.chars()
493 .next()
494 .unwrap()
495 .to_ascii_uppercase()
496 .to_string(),
497 short_name
498 );
499 }
500 }
501
502 #[test]
503 fn level_filter_from_str_for_env() {
504 assert_eq!(
505 LevelFilter::MoreSevereEqual(Level::Info),
506 LevelFilter::from_str_for_env("iNFo").unwrap()
507 );
508
509 assert_eq!(
510 LevelFilter::MoreSevereEqual(Level::Warn),
511 LevelFilter::from_str_for_env("wARn").unwrap()
512 );
513
514 assert_eq!(
515 LevelFilter::Off,
516 LevelFilter::from_str_for_env("oFf").unwrap()
517 );
518
519 assert_eq!(
520 LevelFilter::All,
521 LevelFilter::from_str_for_env("aLl").unwrap()
522 );
523 }
524
525 #[test]
526 fn iter() {
527 let mut iter = Level::iter();
528 assert_eq!(iter.next(), Some(Level::Critical));
529 assert_eq!(iter.next(), Some(Level::Error));
530 assert_eq!(iter.next(), Some(Level::Warn));
531 assert_eq!(iter.next(), Some(Level::Info));
532 assert_eq!(iter.next(), Some(Level::Debug));
533 assert_eq!(iter.next(), Some(Level::Trace));
534 assert_eq!(iter.next(), None);
535 }
536
537 #[test]
538 fn filter() {
539 assert!(!LevelFilter::Off.test(Level::Trace));
540 assert!(!LevelFilter::Off.test(Level::Critical));
541 assert!(!LevelFilter::Off.test(Level::Warn));
542
543 assert!(LevelFilter::Equal(Level::Error).test(Level::Error));
544 assert!(!LevelFilter::Equal(Level::Error).test(Level::Warn));
545 assert!(!LevelFilter::Equal(Level::Error).test(Level::Critical));
546
547 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Trace));
548 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Info));
549 assert!(!LevelFilter::NotEqual(Level::Error).test(Level::Error));
550
551 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Warn));
552 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Error));
553 assert!(!LevelFilter::MoreSevere(Level::Info).test(Level::Info));
554
555 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Warn));
556 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Info));
557 assert!(!LevelFilter::MoreSevereEqual(Level::Info).test(Level::Trace));
558
559 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Warn));
560 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Info));
561 assert!(!LevelFilter::MoreVerbose(Level::Error).test(Level::Error));
562
563 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Warn));
564 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Error));
565 assert!(!LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Critical));
566
567 assert!(LevelFilter::All.test(Level::Trace));
568 assert!(LevelFilter::All.test(Level::Critical));
569 assert!(LevelFilter::All.test(Level::Error));
570 }
571
572 #[cfg(feature = "log")]
573 #[test]
574 fn filter_from_log() {
575 assert_eq!(LevelFilter::from(log::LevelFilter::Off), LevelFilter::Off);
576 assert_eq!(
577 LevelFilter::from(log::LevelFilter::Error),
578 LevelFilter::MoreSevereEqual(Level::Error)
579 );
580 assert_eq!(
581 LevelFilter::from(log::LevelFilter::Warn),
582 LevelFilter::MoreSevereEqual(Level::Warn)
583 );
584 assert_eq!(
585 LevelFilter::from(log::LevelFilter::Info),
586 LevelFilter::MoreSevereEqual(Level::Info)
587 );
588 assert_eq!(
589 LevelFilter::from(log::LevelFilter::Debug),
590 LevelFilter::MoreSevereEqual(Level::Debug)
591 );
592 assert_eq!(
593 LevelFilter::from(log::LevelFilter::Trace),
594 LevelFilter::MoreSevereEqual(Level::Trace)
595 );
596 }
597
598 #[test]
599 fn atomic_level_filter() {
600 let atomic_level_filter = AtomicLevelFilter::new(LevelFilter::All);
601
602 let assert_this = |new: LevelFilter| {
603 assert_ne!(atomic_level_filter.get(), new);
604 atomic_level_filter.set(new);
605 assert_eq!(atomic_level_filter.get(), new);
606 };
607
608 fn produce_all(cond: impl Fn(Level) -> LevelFilter) -> impl Iterator<Item = LevelFilter> {
609 Level::iter().map(cond)
610 }
611
612 assert_this(LevelFilter::Off);
613 produce_all(LevelFilter::Equal).for_each(assert_this);
614 produce_all(LevelFilter::NotEqual).for_each(assert_this);
615 produce_all(LevelFilter::MoreSevere).for_each(assert_this);
616 produce_all(LevelFilter::MoreSevereEqual).for_each(assert_this);
617 produce_all(LevelFilter::MoreVerbose).for_each(assert_this);
618 produce_all(LevelFilter::MoreVerboseEqual).for_each(assert_this);
619 assert_this(LevelFilter::All);
620 }
621
622 #[test]
623 fn level_count() {
624 assert_eq!(Level::iter().count(), Level::count());
625 }
626}