use crate::{LevelFilter, Metadata, Record};
use std::error::Error;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::OnceLock;
use std::{fmt, mem};
pub trait Log: Sync + Send {
fn enabled(&self, metadata: &Metadata<'_>) -> bool;
fn log(&self, record: &Record<'_>);
fn flush(&self);
}
struct NopLogger;
impl Log for NopLogger {
fn enabled(&self, _: &Metadata<'_>) -> bool {
false
}
fn log(&self, _: &Record<'_>) {}
fn flush(&self) {}
}
static LOGGER: OnceLock<&'static dyn Log> = OnceLock::new();
pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
LOGGER.set(logger).map_err(|_| SetLoggerError(()))
}
pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {
let mut logger = Some(logger);
LOGGER.get_or_init(|| Box::leak(logger.take().unwrap()));
match logger {
Some(_) => Err(SetLoggerError(())),
None => Ok(()),
}
}
pub fn logger() -> &'static dyn Log {
LOGGER.get().map_or(&NopLogger, |l| *l)
}
#[derive(Debug)]
pub struct SetLoggerError(());
impl fmt::Display for SetLoggerError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("a logger is already installed")
}
}
impl Error for SetLoggerError {}
static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0);
pub fn set_max_level(level: LevelFilter) {
MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed);
}
#[inline(always)]
pub fn max_level() -> LevelFilter {
unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) }
}