From 3f4f25a2d7b2e640221e8b4e5a553428fb605cb0 Mon Sep 17 00:00:00 2001 From: piegames Date: Mon, 15 Nov 2021 23:53:54 +0100 Subject: [PATCH] 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.) --- src/lib.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index bfd0819..5dfb914 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 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 Log for std::boxed::Box where @@ -1267,6 +1283,41 @@ where } } +#[cfg(feature = "std")] +impl Log for std::pin::Pin

+where + P: std::ops::Deref + 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 Log for std::sync::Arc +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() {} + + assert_is_log::<&dyn Log>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + + #[cfg(feature = "std")] + assert_is_log::>>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + + // Assert these statements for all T: Log + ?Sized + #[allow(unused)] + fn forall() { + #[cfg(feature = "std")] + assert_is_log::>(); + + #[cfg(feature = "std")] + assert_is_log::>>(); + + assert_is_log::<&T>(); + + #[cfg(feature = "std")] + assert_is_log::>(); + } + } }