diff --git a/src/kv/value.rs b/src/kv/value.rs index 5e79bb816..f9e2a677b 100644 --- a/src/kv/value.rs +++ b/src/kv/value.rs @@ -373,6 +373,35 @@ impl_value_to_primitive![ to_bool -> bool, ]; +#[cfg(feature = "std")] +macro_rules! impl_to_value_from_display { + ($($into_ty:ty,)*) => { + $( + impl ToValue for $into_ty { + fn to_value(&self) -> Value<'_> { + Value::from_display(self) + } + } + + impl<'v> From<&'v $into_ty> for Value<'v> { + fn from(value: &'v $into_ty) -> Self { + Value::from_display(value) + } + } + )* + }; +} + +#[cfg(feature = "std")] +impl_to_value_from_display![ + std::net::IpAddr, + std::net::Ipv4Addr, + std::net::Ipv6Addr, + std::net::SocketAddr, + std::net::SocketAddrV4, + std::net::SocketAddrV6, +]; + impl<'v> Value<'v> { /// Try to convert this value into an error. #[cfg(feature = "kv_std")] @@ -736,6 +765,7 @@ pub(in crate::kv) mod inner { #[derive(Clone)] pub enum Inner<'v> { + // NOTE: New variants can't be added here; see the module-level doc above None, Bool(bool), Str(&'v str), @@ -999,7 +1029,7 @@ pub(in crate::kv) mod inner { } #[cfg(test)] - pub fn to_test_token(&self) -> Token { + pub fn to_test_token(&self) -> Token<'_> { match self { Inner::None => Token::None, Inner::Bool(v) => Token::Bool(*v), @@ -1176,7 +1206,10 @@ macro_rules! as_sval { pub(crate) mod tests { use super::*; + // For new `ToValue` implementations, also add a test to the `tests/macros` file + impl<'v> Value<'v> { + #[allow(mismatched_lifetime_syntaxes)] pub(crate) fn to_token(&self) -> inner::Token { self.inner.to_test_token() } @@ -1243,6 +1276,75 @@ pub(crate) mod tests { assert_eq!(None::.to_value().to_string(), "None"); } + #[test] + #[cfg(feature = "std")] + fn test_net_to_value_display() { + use std::str::FromStr; + + assert_eq!( + std::net::Ipv4Addr::new(192, 168, 10, 100) + .to_value() + .to_string(), + "192.168.10.100" + ); + assert_eq!( + std::net::Ipv6Addr::from_str("f33c::1") + .unwrap() + .to_value() + .to_string(), + "f33c::1" + ); + assert_eq!( + std::net::IpAddr::V4(std::net::Ipv4Addr::new(192, 168, 10, 100)) + .to_value() + .to_string(), + "192.168.10.100" + ); + assert_eq!( + std::net::IpAddr::V6(std::net::Ipv6Addr::from_str("f33c::1").unwrap()) + .to_value() + .to_string(), + "f33c::1" + ); + assert_eq!( + std::net::SocketAddrV4::new(std::net::Ipv4Addr::new(192, 168, 10, 100), 12345) + .to_value() + .to_string(), + "192.168.10.100:12345" + ); + assert_eq!( + std::net::SocketAddrV6::new( + std::net::Ipv6Addr::from_str("f33c::1").unwrap(), + 12345, + 0, + 0 + ) + .to_value() + .to_string(), + "[f33c::1]:12345" + ); + assert_eq!( + std::net::SocketAddr::V4(std::net::SocketAddrV4::new( + std::net::Ipv4Addr::new(192, 168, 10, 100), + 12345 + )) + .to_value() + .to_string(), + "192.168.10.100:12345" + ); + assert_eq!( + std::net::SocketAddr::V6(std::net::SocketAddrV6::new( + std::net::Ipv6Addr::from_str("f33c::1").unwrap(), + 12345, + 0, + 0 + )) + .to_value() + .to_string(), + "[f33c::1]:12345" + ); + } + #[test] fn test_to_value_structured() { assert_eq!(42u64.to_value().to_token(), inner::Token::U64(42)); diff --git a/tests/macros.rs b/tests/macros.rs index dded475c1..fa8b84eec 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -415,6 +415,27 @@ fn logger_expr() { }, "hello"); } +#[cfg(all(feature = "std", feature = "kv"))] +#[test] +fn kv_net() { + use std::{ + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, + str::FromStr, + }; + + all_log_macros!( + a = Ipv4Addr::new(192, 168, 10, 100), + b = Ipv6Addr::from_str("f33c::1").unwrap(), + c = IpAddr::V4(Ipv4Addr::new(192, 168, 10, 100)), + d = IpAddr::V6(Ipv6Addr::from_str("f33c::1").unwrap()), + e = SocketAddrV4::new(Ipv4Addr::new(192, 168, 10, 100), 12345), + f = SocketAddrV6::new(Ipv6Addr::from_str("f33c::1").unwrap(), 12345, 0, 0), + g = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 10, 100), 12345)), + h = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from_str("f33c::1").unwrap(), 12345, 0, 0)); + "hello world" + ); +} + /// Some and None (from Option) are used in the macros. #[derive(Debug)] enum Type {