Add Log implementation on foreign types

Closes #458. Implements Log for references to loggers, as well as loggers wrapped
in `Arc` or `Pin`. More may be added in the future. Especially, we probably will
want to add a blanket implementation (bounded on `Borrow`) once we have impl
specialization. (Technically, we could probably already do this now, but at the
risk of painting ourselves into a corner.)
This commit is contained in:
piegames
2021-11-15 23:53:54 +01:00
parent 888d37c3fb
commit 3f4f25a2d7
+89 -1
View File
@@ -269,7 +269,7 @@
html_root_url = "https://docs.rs/log/0.4.14"
)]
#![warn(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(missing_debug_implementations, unconditional_recursion)]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
// When compiled for the rustc compiler itself we want to make sure that this is
// an unstable crate
@@ -1250,6 +1250,22 @@ impl Log for NopLogger {
fn flush(&self) {}
}
impl<T> Log for &'_ T
where
T: ?Sized + Log,
{
fn enabled(&self, metadata: &Metadata) -> bool {
(**self).enabled(metadata)
}
fn log(&self, record: &Record) {
(**self).log(record)
}
fn flush(&self) {
(**self).flush()
}
}
#[cfg(feature = "std")]
impl<T> Log for std::boxed::Box<T>
where
@@ -1267,6 +1283,41 @@ where
}
}
#[cfg(feature = "std")]
impl<P, T> Log for std::pin::Pin<P>
where
P: std::ops::Deref<Target = T> + std::marker::Send + std::marker::Sync,
T: Log + ?Sized,
{
fn enabled(&self, metadata: &Metadata) -> bool {
(**self).enabled(metadata)
}
fn log(&self, record: &Record) {
(**self).log(record)
}
fn flush(&self) {
(**self).flush()
}
}
#[cfg(feature = "std")]
impl<T> Log for std::sync::Arc<T>
where
T: ?Sized + Log,
{
fn enabled(&self, metadata: &Metadata) -> bool {
self.as_ref().enabled(metadata)
}
fn log(&self, record: &Record) {
self.as_ref().log(record)
}
fn flush(&self) {
self.as_ref().flush()
}
}
/// Sets the global maximum log level.
///
/// Generally, this should only be called by the active logging implementation.
@@ -1842,4 +1893,41 @@ mod tests {
.expect("invalid value")
);
}
// Test that the `impl Log for Foo` blocks work
// This test mostly operates on a type level, so failures will be compile errors
#[test]
fn test_foreign_impl() {
use super::Log;
#[cfg(feature = "std")]
use std::{pin::Pin, sync::Arc};
fn assert_is_log<T: Log + ?Sized>() {}
assert_is_log::<&dyn Log>();
#[cfg(feature = "std")]
assert_is_log::<Box<dyn Log>>();
#[cfg(feature = "std")]
assert_is_log::<Pin<Box<dyn Log>>>();
#[cfg(feature = "std")]
assert_is_log::<Arc<dyn Log>>();
// Assert these statements for all T: Log + ?Sized
#[allow(unused)]
fn forall<T: Log + ?Sized>() {
#[cfg(feature = "std")]
assert_is_log::<Box<T>>();
#[cfg(feature = "std")]
assert_is_log::<Pin<Box<T>>>();
assert_is_log::<&T>();
#[cfg(feature = "std")]
assert_is_log::<Arc<T>>();
}
}
}