From ba272f92f1e1452e2cf0561fc25630fdac83752b Mon Sep 17 00:00:00 2001 From: EFanZh Date: Sun, 13 Aug 2023 15:57:07 +0800 Subject: [PATCH] Specialize empty key value pairs --- src/__private_api.rs | 117 ++++++++++++++++++++++++++++++++----------- src/macros.rs | 6 +-- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/__private_api.rs b/src/__private_api.rs index 7304deb89..5a1ecb2b3 100644 --- a/src/__private_api.rs +++ b/src/__private_api.rs @@ -1,57 +1,116 @@ //! WARNING: this is not part of the crate's public API and is subject to change at any time +use self::sealed::KVs; use crate::{Level, Metadata, Record}; use std::fmt::Arguments; -pub use std::option::Option; pub use std::{file, format_args, line, module_path, stringify}; +#[cfg(feature = "kv_unstable")] +pub type Value<'a> = dyn crate::kv::value::ToValue + 'a; + #[cfg(not(feature = "kv_unstable"))] -pub fn log( +pub type Value<'a> = str; + +mod sealed { + /// Argument that provides key-value pairs. + pub trait KVs<'a> { + fn into_kvs(self) -> Option<&'a [(&'a str, &'a super::Value<'a>)]>; + } +} + +// key values. + +impl<'a> KVs<'a> for &'a [(&'a str, &'a Value<'a>)] { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, &'a Value<'a>)]> { + Some(self) + } +} + +impl<'a> KVs<'a> for () { + #[inline] + fn into_kvs(self) -> Option<&'a [(&'a str, &'a Value<'a>)]> { + None + } +} + +// Log implementation. + +fn log_impl( args: Arguments, level: Level, &(target, module_path, file): &(&str, &'static str, &'static str), line: u32, - kvs: Option<&[(&str, &str)]>, + kvs: Option<&[(&str, &Value)]>, ) { + #[cfg(not(feature = "kv_unstable"))] if kvs.is_some() { panic!( "key-value support is experimental and must be enabled using the `kv_unstable` feature" ) } - crate::logger().log( - &Record::builder() - .args(args) - .level(level) - .target(target) - .module_path_static(Some(module_path)) - .file_static(Some(file)) - .line(Some(line)) - .build(), - ); + let mut builder = Record::builder(); + + builder + .args(args) + .level(level) + .target(target) + .module_path_static(Some(module_path)) + .file_static(Some(file)) + .line(Some(line)); + + #[cfg(feature = "kv_unstable")] + builder.key_values(&kvs); + + crate::logger().log(&builder.build()); } -#[cfg(feature = "kv_unstable")] -pub fn log( +pub fn log<'a, K>( args: Arguments, level: Level, - &(target, module_path, file): &(&str, &'static str, &'static str), + target_module_path_and_file: &(&str, &'static str, &'static str), line: u32, - kvs: Option<&[(&str, &dyn crate::kv::ToValue)]>, -) { - crate::logger().log( - &Record::builder() - .args(args) - .level(level) - .target(target) - .module_path_static(Some(module_path)) - .file_static(Some(file)) - .line(Some(line)) - .key_values(&kvs) - .build(), - ); + kvs: K, +) where + K: KVs<'a>, +{ + log_impl( + args, + level, + target_module_path_and_file, + line, + kvs.into_kvs(), + ) } pub fn enabled(level: Level, target: &str) -> bool { crate::logger().enabled(&Metadata::builder().level(level).target(target).build()) } + +/// This function is not intended to be actually called by anyone. The intention of this function is for forcing the +/// compiler to generate monomorphizations of the `log` function, so that they can be shared by different downstream +/// crates. +/// +/// The idea is that with [`share-generics`](https://github.com/rust-lang/rust/pull/48779), downstream crates can reuse +/// generic monomorphizations from upstream crates, but not siblings crates. So it is best to instantiate these +/// monomorphizations in the `log` crate, so downstream crates are guaranteed to be able to share them. +pub fn instantiate_log_function() -> usize { + struct State(usize); + + impl State { + fn add<'a, K>(&mut self) + where + K: KVs<'a>, + { + self.0 ^= log:: as usize; + } + } + + let mut state = State(0); + + state.add::<&[(&str, &Value)]>(); + state.add::<()>(); + + state.0 +} diff --git a/src/macros.rs b/src/macros.rs index 281ff2572..30d7c10a0 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -33,12 +33,12 @@ macro_rules! log { (target: $target:expr, $lvl:expr, $($key:tt = $value:expr),+; $($arg:tt)+) => ({ let lvl = $lvl; if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { - $crate::__private_api::log( + $crate::__private_api::log::<&_>( $crate::__private_api::format_args!($($arg)+), lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::file!()), $crate::__private_api::line!(), - $crate::__private_api::Option::Some(&[$(($crate::__log_key!($key), &$value)),+]) + &[$(($crate::__log_key!($key), &$value)),+] ); } }); @@ -52,7 +52,7 @@ macro_rules! log { lvl, &($target, $crate::__private_api::module_path!(), $crate::__private_api::file!()), $crate::__private_api::line!(), - $crate::__private_api::Option::None, + (), ); } });