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 pub fn new(init: LevelFilter) -> Self {
383 Self {
384 inner: atomic::Atomic::new(init.into()),
385 }
386 }
387
388 pub fn get(&self) -> LevelFilter {
390 self.load(Self::ORDERING)
391 }
392
393 pub fn set(&self, new: LevelFilter) {
395 self.store(new, Self::ORDERING);
396 }
397
398 pub fn load(&self, ordering: Ordering) -> LevelFilter {
404 self.inner.load(ordering).into()
405 }
406
407 pub fn store(&self, value: LevelFilter, ordering: Ordering) {
413 self.inner.store(value.into(), ordering);
414 }
415
416 pub fn swap(&self, new: LevelFilter, ordering: Ordering) -> LevelFilter {
418 self.inner.swap(new.into(), ordering).into()
419 }
420}
421
422impl Debug for AtomicLevelFilter {
423 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
424 self.get().fmt(f)
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use std::mem::size_of;
431
432 use super::*;
433 use crate::utils::const_assert;
434
435 const_assert!(atomic::Atomic::<Level>::is_lock_free());
436 const_assert!(atomic::Atomic::<LevelFilter>::is_lock_free());
437 const_assert!(atomic::Atomic::<LevelFilterLayout>::is_lock_free());
438 const_assert!(size_of::<Level>() * 2 == size_of::<LevelFilter>());
439 const_assert!(align_of::<Level>() * 2 == align_of::<LevelFilter>());
440 const_assert!(size_of::<LevelFilter>() == size_of::<LevelFilterLayout>());
441 const_assert!(align_of::<LevelFilter>() == align_of::<LevelFilterLayout>());
442
443 #[test]
444 fn from_usize() {
445 assert_eq!(
446 Level::most_severe(),
447 Level::from_usize(Level::min_usize()).unwrap()
448 );
449
450 assert_eq!(
451 Level::most_verbose(),
452 Level::from_usize(Level::max_usize()).unwrap()
453 );
454 }
455
456 #[test]
457 fn from_str() {
458 fn to_random_case(input: &str) -> String {
459 input
460 .char_indices()
461 .map(|(i, char)| {
462 if i % 2 != 0 {
463 char.to_ascii_uppercase()
464 } else {
465 char.to_ascii_lowercase()
466 }
467 })
468 .collect::<String>()
469 }
470
471 for (i, &name) in LOG_LEVEL_NAMES.iter().enumerate() {
472 let from_usize = Level::from_usize(i);
473 let from_str = (
474 Level::from_str(&name.to_lowercase()),
475 Level::from_str(&name.to_uppercase()),
476 Level::from_str(&to_random_case(name)),
477 );
478
479 assert_eq!(from_usize.unwrap(), from_str.0.unwrap());
480 assert_eq!(from_usize.unwrap(), from_str.1.unwrap());
481 assert_eq!(from_usize.unwrap(), from_str.2.unwrap());
482 }
483
484 assert!(Level::from_str("notexist").is_err());
485 }
486
487 #[test]
488 fn as_short_str() {
489 for (&name, &short_name) in LOG_LEVEL_NAMES.iter().zip(LOG_LEVEL_SHORT_NAMES.iter()) {
490 assert_eq!(
491 name.chars()
492 .next()
493 .unwrap()
494 .to_ascii_uppercase()
495 .to_string(),
496 short_name
497 );
498 }
499 }
500
501 #[test]
502 fn level_filter_from_str_for_env() {
503 assert_eq!(
504 LevelFilter::MoreSevereEqual(Level::Info),
505 LevelFilter::from_str_for_env("iNFo").unwrap()
506 );
507
508 assert_eq!(
509 LevelFilter::MoreSevereEqual(Level::Warn),
510 LevelFilter::from_str_for_env("wARn").unwrap()
511 );
512
513 assert_eq!(
514 LevelFilter::Off,
515 LevelFilter::from_str_for_env("oFf").unwrap()
516 );
517
518 assert_eq!(
519 LevelFilter::All,
520 LevelFilter::from_str_for_env("aLl").unwrap()
521 );
522 }
523
524 #[test]
525 fn iter() {
526 let mut iter = Level::iter();
527 assert_eq!(iter.next(), Some(Level::Critical));
528 assert_eq!(iter.next(), Some(Level::Error));
529 assert_eq!(iter.next(), Some(Level::Warn));
530 assert_eq!(iter.next(), Some(Level::Info));
531 assert_eq!(iter.next(), Some(Level::Debug));
532 assert_eq!(iter.next(), Some(Level::Trace));
533 assert_eq!(iter.next(), None);
534 }
535
536 #[test]
537 fn filter() {
538 assert!(!LevelFilter::Off.test(Level::Trace));
539 assert!(!LevelFilter::Off.test(Level::Critical));
540 assert!(!LevelFilter::Off.test(Level::Warn));
541
542 assert!(LevelFilter::Equal(Level::Error).test(Level::Error));
543 assert!(!LevelFilter::Equal(Level::Error).test(Level::Warn));
544 assert!(!LevelFilter::Equal(Level::Error).test(Level::Critical));
545
546 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Trace));
547 assert!(LevelFilter::NotEqual(Level::Error).test(Level::Info));
548 assert!(!LevelFilter::NotEqual(Level::Error).test(Level::Error));
549
550 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Warn));
551 assert!(LevelFilter::MoreSevere(Level::Info).test(Level::Error));
552 assert!(!LevelFilter::MoreSevere(Level::Info).test(Level::Info));
553
554 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Warn));
555 assert!(LevelFilter::MoreSevereEqual(Level::Info).test(Level::Info));
556 assert!(!LevelFilter::MoreSevereEqual(Level::Info).test(Level::Trace));
557
558 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Warn));
559 assert!(LevelFilter::MoreVerbose(Level::Error).test(Level::Info));
560 assert!(!LevelFilter::MoreVerbose(Level::Error).test(Level::Error));
561
562 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Warn));
563 assert!(LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Error));
564 assert!(!LevelFilter::MoreVerboseEqual(Level::Error).test(Level::Critical));
565
566 assert!(LevelFilter::All.test(Level::Trace));
567 assert!(LevelFilter::All.test(Level::Critical));
568 assert!(LevelFilter::All.test(Level::Error));
569 }
570
571 #[cfg(feature = "log")]
572 #[test]
573 fn filter_from_log() {
574 assert_eq!(LevelFilter::from(log::LevelFilter::Off), LevelFilter::Off);
575 assert_eq!(
576 LevelFilter::from(log::LevelFilter::Error),
577 LevelFilter::MoreSevereEqual(Level::Error)
578 );
579 assert_eq!(
580 LevelFilter::from(log::LevelFilter::Warn),
581 LevelFilter::MoreSevereEqual(Level::Warn)
582 );
583 assert_eq!(
584 LevelFilter::from(log::LevelFilter::Info),
585 LevelFilter::MoreSevereEqual(Level::Info)
586 );
587 assert_eq!(
588 LevelFilter::from(log::LevelFilter::Debug),
589 LevelFilter::MoreSevereEqual(Level::Debug)
590 );
591 assert_eq!(
592 LevelFilter::from(log::LevelFilter::Trace),
593 LevelFilter::MoreSevereEqual(Level::Trace)
594 );
595 }
596
597 #[test]
598 fn atomic_level_filter() {
599 let atomic_level_filter = AtomicLevelFilter::new(LevelFilter::All);
600
601 let assert_this = |new: LevelFilter| {
602 assert_ne!(atomic_level_filter.get(), new);
603 atomic_level_filter.set(new);
604 assert_eq!(atomic_level_filter.get(), new);
605 };
606
607 fn produce_all(cond: impl Fn(Level) -> LevelFilter) -> impl Iterator<Item = LevelFilter> {
608 Level::iter().map(cond)
609 }
610
611 assert_this(LevelFilter::Off);
612 produce_all(LevelFilter::Equal).for_each(assert_this);
613 produce_all(LevelFilter::NotEqual).for_each(assert_this);
614 produce_all(LevelFilter::MoreSevere).for_each(assert_this);
615 produce_all(LevelFilter::MoreSevereEqual).for_each(assert_this);
616 produce_all(LevelFilter::MoreVerbose).for_each(assert_this);
617 produce_all(LevelFilter::MoreVerboseEqual).for_each(assert_this);
618 assert_this(LevelFilter::All);
619 }
620}