use std::sync::Arc;
#[derive(Clone)]
struct SerdeArc(Arc<dyn erased_serde::Serialize + Send + Sync + 'static>);
impl SerdeArc {
fn new<T>(value: T) -> Self
where
T: serde::Serialize + Send + Sync + 'static,
{
Self(Arc::new(value))
}
}
impl serde::Serialize for SerdeArc {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
erased_serde::serialize(&*self.0, serializer)
}
}
#[derive(Clone)]
pub struct LogValue(LogValueInner);
#[derive(Clone)]
enum LogValueInner {
Null,
String(String),
Bool(bool),
Char(char),
I64(i64),
U64(u64),
F64(f64),
I128(i128),
U128(u128),
Debug(Arc<dyn std::fmt::Debug + Send + Sync + 'static>),
Display(Arc<dyn std::fmt::Display + Send + Sync + 'static>),
Error(Arc<dyn std::error::Error + Send + Sync + 'static>),
Serde(SerdeArc),
}
impl From<LogValueInner> for LogValue {
fn from(inner: LogValueInner) -> Self {
Self(inner)
}
}
impl LogValue {
#[allow(clippy::must_use_candidate)]
pub fn null() -> Self {
LogValueInner::Null.into()
}
pub fn serde<S>(value: S) -> Self
where
S: serde::Serialize + Send + Sync + 'static,
{
LogValueInner::Serde(SerdeArc::new(value)).into()
}
pub fn display<T>(value: T) -> Self
where
T: std::fmt::Display + Send + Sync + 'static,
{
LogValueInner::Display(Arc::new(value)).into()
}
pub fn debug<T>(value: T) -> Self
where
T: std::fmt::Debug + Send + Sync + 'static,
{
LogValueInner::Debug(Arc::new(value)).into()
}
pub fn error<T>(value: T) -> Self
where
T: std::error::Error + Send + Sync + 'static,
{
LogValueInner::Error(Arc::new(value)).into()
}
#[must_use]
pub fn as_log_value(&self) -> log::kv::Value<'_> {
match &self.0 {
LogValueInner::Null => log::kv::Value::null(),
LogValueInner::String(s) => log::kv::Value::from(&**s),
LogValueInner::Bool(b) => log::kv::Value::from(*b),
LogValueInner::Char(c) => log::kv::Value::from(*c),
LogValueInner::I64(i) => log::kv::Value::from(*i),
LogValueInner::U64(u) => log::kv::Value::from(*u),
LogValueInner::F64(f) => log::kv::Value::from(*f),
LogValueInner::I128(i) => log::kv::Value::from(*i),
LogValueInner::U128(u) => log::kv::Value::from(*u),
LogValueInner::Display(value) => log::kv::Value::from_dyn_display(&**value),
LogValueInner::Debug(value) => log::kv::Value::from_dyn_debug(&**value),
LogValueInner::Error(value) => log::kv::Value::from_dyn_error(&**value),
LogValueInner::Serde(value) => log::kv::Value::from_serde(value),
}
}
}
macro_rules! impl_log_value_from_primitive {
($($ty:ty => $arm:ident),*) => {
$(
impl From<$ty> for LogValue {
fn from(value: $ty) -> Self {
LogValue(LogValueInner::$arm(value.into()))
}
}
)*
};
}
impl_log_value_from_primitive!(
bool => Bool,
char => Char,
&str => String,
std::borrow::Cow<'_, str> => String,
String => String,
i8 => I64,
i16 => I64,
i32 => I64,
i64 => I64,
u8 => U64,
u16 => U64,
u32 => U64,
u64 => U64,
f32 => F64,
f64 => F64,
i128 => I128,
u128 => U128
);
impl std::fmt::Display for LogValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_log_value().fmt(f)
}
}
impl std::fmt::Debug for LogValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_log_value().fmt(f)
}
}