From db145979e229549215300f2696fa89b215cb1cab Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 1 Jun 2026 12:21:32 +0800 Subject: [PATCH 1/3] Leverage static str key when possible Signed-off-by: tison --- src/__private_api.rs | 13 ++++++++----- src/kv/key.rs | 37 +++++++++++++++++++++++++++---------- src/macros.rs | 4 ++-- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/__private_api.rs b/src/__private_api.rs index 8d4446727..09e7a7ed6 100644 --- a/src/__private_api.rs +++ b/src/__private_api.rs @@ -6,28 +6,30 @@ use std::fmt::Arguments; use std::panic::Location; pub use std::{format_args, module_path, stringify}; +#[cfg(not(feature = "kv"))] +pub type Key<'a> = &'a str; #[cfg(not(feature = "kv"))] pub type Value<'a> = &'a str; mod sealed { /// Types for the `kv` argument. pub trait KVs<'a> { - fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>; + fn into_kvs(self) -> Option<&'a [(super::Key<'a>, super::Value<'a>)]>; } } // Types for the `kv` argument. -impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] { +impl<'a> KVs<'a> for &'a [(Key<'a>, Value<'a>)] { #[inline] - fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + fn into_kvs(self) -> Option<&'a [(Key<'a>, Value<'a>)]> { Some(self) } } impl<'a> KVs<'a> for () { #[inline] - fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> { + fn into_kvs(self) -> Option<&'a [(Key<'a>, Value<'a>)]> { None } } @@ -58,7 +60,7 @@ fn log_impl( args: Arguments, level: Level, &(target, module_path, loc): &(&str, &'static str, &'static Location), - kvs: Option<&[(&str, Value)]>, + kvs: Option<&[(Key, Value)]>, ) { #[cfg(not(feature = "kv"))] if kvs.is_some() { @@ -113,6 +115,7 @@ pub fn loc() -> &'static Location<'static> { mod kv_support { use crate::kv; + pub type Key<'a> = kv::Key<'a>; pub type Value<'a> = kv::Value<'a>; // NOTE: Many functions here accept a double reference &&V diff --git a/src/kv/key.rs b/src/kv/key.rs index f0557d0cf..bc8c315e5 100644 --- a/src/kv/key.rs +++ b/src/kv/key.rs @@ -1,5 +1,6 @@ //! Structured keys. +use crate::MaybeStaticStr; use std::borrow::Borrow; use std::fmt; @@ -35,15 +36,23 @@ impl ToKey for str { // If a new field (such as an optional index) is added to the key they must not affect comparison #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Key<'k> { - // NOTE: This may become `Cow<'k, str>` - key: &'k str, + key: MaybeStaticStr<'k>, } impl<'k> Key<'k> { /// Get a key from a borrowed string. #[allow(clippy::should_implement_trait)] // Part of the public API now. pub fn from_str(key: &'k str) -> Self { - Key { key } + Key { + key: MaybeStaticStr::Borrowed(key), + } + } + + /// Get a key from a static str. + pub fn from_static_str(key: &'static str) -> Self { + Key { + key: MaybeStaticStr::Static(key), + } } /// Get a borrowed string from this key. @@ -51,10 +60,10 @@ impl<'k> Key<'k> { /// The lifetime of the returned string is bound to the borrow of `self` rather /// than to `'k`. pub fn as_str(&self) -> &str { - self.key + self.key.get() } - /// Try get a borrowed string for the lifetime `'k` from this key. + /// Try to get a borrowed string for the lifetime `'k` from this key. /// /// If the key is a borrow of a longer lived string, this method will return `Some`. /// If the key is internally buffered, this method will return `None`. @@ -62,13 +71,21 @@ impl<'k> Key<'k> { // NOTE: If the internals of `Key` support buffering this // won't be unconditionally `Some` anymore. We want to keep // this option open - Some(self.key) + Some(self.key.get()) + } + + /// Try to get a static string from this key. + pub fn to_static_str(&self) -> Option<&'static str> { + match self.key { + MaybeStaticStr::Static(s) => Some(s), + MaybeStaticStr::Borrowed(_) => None, + } } } impl<'k> fmt::Display for Key<'k> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.key.fmt(f) + self.key.get().fmt(f) } } @@ -121,13 +138,13 @@ mod sval_support { &'sval self, stream: &mut S, ) -> sval::Result { - self.key.stream(stream) + self.key.get().stream(stream) } } impl<'a> ValueRef<'a> for Key<'a> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { - self.key.stream(stream) + self.key.get().stream(stream) } } } @@ -143,7 +160,7 @@ mod serde_support { where S: Serializer, { - self.key.serialize(serializer) + self.key.get().serialize(serializer) } } } diff --git a/src/macros.rs b/src/macros.rs index 958708726..bb0cb55a9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -445,11 +445,11 @@ macro_rules! __log_logger { macro_rules! __log_key { // key1 = 42 ($($args:ident)*) => { - $crate::__private_api::stringify!($($args)*) + $crate::__private_api::Key::from_static_str($crate::__private_api::stringify!($($args)*)) }; // "key1" = 42 ($($args:expr)*) => { - $($args)* + $crate::__private_api::Key::from_str($($args)*) }; } From 3dd250d1537fd7e5974e0802b1025cc3e4561503 Mon Sep 17 00:00:00 2001 From: tison Date: Tue, 2 Jun 2026 01:11:03 +0800 Subject: [PATCH 2/3] rename Key::from_static_str to from_str_static Signed-off-by: tison --- src/kv/key.rs | 2 +- src/macros.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kv/key.rs b/src/kv/key.rs index bc8c315e5..12ee16a82 100644 --- a/src/kv/key.rs +++ b/src/kv/key.rs @@ -49,7 +49,7 @@ impl<'k> Key<'k> { } /// Get a key from a static str. - pub fn from_static_str(key: &'static str) -> Self { + pub fn from_str_static(key: &'static str) -> Self { Key { key: MaybeStaticStr::Static(key), } diff --git a/src/macros.rs b/src/macros.rs index bb0cb55a9..337580a16 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -445,7 +445,7 @@ macro_rules! __log_logger { macro_rules! __log_key { // key1 = 42 ($($args:ident)*) => { - $crate::__private_api::Key::from_static_str($crate::__private_api::stringify!($($args)*)) + $crate::__private_api::Key::from_str_static($crate::__private_api::stringify!($($args)*)) }; // "key1" = 42 ($($args:expr)*) => { From 756c279649f79ce0ef8dccf952c5df4017791d1c Mon Sep 17 00:00:00 2001 From: tison Date: Tue, 2 Jun 2026 01:15:34 +0800 Subject: [PATCH 3/3] leverage str literal as well Signed-off-by: tison --- src/macros.rs | 12 ++++++++---- tests/macros.rs | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 337580a16..1e766997b 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -444,12 +444,16 @@ macro_rules! __log_logger { #[cfg(feature = "kv")] macro_rules! __log_key { // key1 = 42 - ($($args:ident)*) => { - $crate::__private_api::Key::from_str_static($crate::__private_api::stringify!($($args)*)) + ($args:ident) => { + $crate::__private_api::Key::from_str_static($crate::__private_api::stringify!($args)) }; // "key1" = 42 - ($($args:expr)*) => { - $crate::__private_api::Key::from_str($($args)*) + ($args:literal) => { + $crate::__private_api::Key::from_str_static($args) + }; + // key = 42, where key is an expression + ($args:expr) => { + $crate::__private_api::Key::from_str($args) }; } diff --git a/tests/macros.rs b/tests/macros.rs index fa8b84eec..e4b66cd28 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -269,6 +269,16 @@ fn kv_ident() { all_log_macros!(cat_1, cat_2:%, cat_count = 2; "hello {world}", world = "world"); } +#[test] +#[cfg(feature = "kv")] +fn kv_static_keys() { + assert_eq!(Some("cat_1"), log::__log_key!(cat_1).to_static_str()); + assert_eq!(Some("cat_1"), log::__log_key!("cat_1").to_static_str()); + + let cat_1 = "chashu".to_string(); + assert_eq!(None, log::__log_key!(cat_1.as_str()).to_static_str()); +} + #[test] #[cfg(feature = "kv")] fn kv_expr_context() {