Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ unsafe impl Sync for AtomicUsize {}

// The LOGGER static holds a pointer to the global logger. It is protected by
// the STATE static which determines whether LOGGER has been initialized yet.
static mut LOGGER: &dyn Log = &NopLogger;
static mut LOGGER: &dyn LogAny = &NopLogger;

static STATE: AtomicUsize = AtomicUsize::new(0);

Expand Down Expand Up @@ -1314,6 +1314,26 @@ pub trait Log: Sync + Send {
fn flush(&self);
}

/// helper trait for downcasting a `dyn Log` into a concrete type through [`std::any::Any`]
pub trait LogAny: Log + std::any::Any {
/// Turns the return value of [`logger`] into an Any value for downcasting
///
/// # For implementors
///
/// The defeault implementation should probably never be overwritten,
/// though it is valid to do so, there is probably never a good reason.
fn as_any(&'static self) -> &'static dyn std::any::Any;
}

impl<T> LogAny for T
where
T: Log + std::any::Any,
{
fn as_any(&'static self) -> &'static dyn std::any::Any {
self
}
}

/// A dummy initial value for LOGGER.
struct NopLogger;

Expand Down Expand Up @@ -1452,7 +1472,7 @@ pub fn max_level() -> LevelFilter {
///
/// [`set_logger`]: fn.set_logger.html
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {
pub fn set_boxed_logger(logger: Box<dyn LogAny>) -> Result<(), SetLoggerError> {
set_logger_inner(|| Box::leak(logger))
}

Expand Down Expand Up @@ -1510,14 +1530,14 @@ pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {
///
/// [`set_logger_racy`]: fn.set_logger_racy.html
#[cfg(target_has_atomic = "ptr")]
pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
pub fn set_logger(logger: &'static dyn LogAny) -> Result<(), SetLoggerError> {
set_logger_inner(|| logger)
}

#[cfg(target_has_atomic = "ptr")]
fn set_logger_inner<F>(make_logger: F) -> Result<(), SetLoggerError>
where
F: FnOnce() -> &'static dyn Log,
F: FnOnce() -> &'static dyn LogAny,
{
match STATE.compare_exchange(
UNINITIALIZED,
Expand Down Expand Up @@ -1561,7 +1581,7 @@ where
/// (including all logging macros).
///
/// [`set_logger`]: fn.set_logger.html
pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
pub unsafe fn set_logger_racy(logger: &'static dyn LogAny) -> Result<(), SetLoggerError> {
match STATE.load(Ordering::Acquire) {
UNINITIALIZED => {
LOGGER = logger;
Expand Down Expand Up @@ -1613,7 +1633,7 @@ impl error::Error for ParseLevelError {}
/// Returns a reference to the logger.
///
/// If a logger has not been set, a no-op implementation is returned.
pub fn logger() -> &'static dyn Log {
pub fn logger() -> &'static dyn LogAny {
// Acquire memory ordering guarantees that current thread would see any
// memory writes that happened before store of the value
// into `STATE` with memory ordering `Release` or stronger.
Expand Down
4 changes: 2 additions & 2 deletions test_max_level_features/main.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use log::{debug, error, info, trace, warn, Level, LevelFilter, Log, Metadata, Record};
use log::{debug, error, info, trace, warn, Level, LevelFilter, Log, LogAny, Metadata, Record};
use std::sync::{Arc, Mutex};

#[cfg(feature = "std")]
use log::set_boxed_logger;
#[cfg(not(feature = "std"))]
fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), log::SetLoggerError> {
fn set_boxed_logger(logger: Box<dyn LogAny>) -> Result<(), log::SetLoggerError> {
log::set_logger(Box::leak(logger))
}

Expand Down
Loading