use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
pub(crate) const TRACING_FIELDS_STRUCTURE_NAME: &str =
"tracing_fields:fc848aeb-3723-438e-b3c3-35162b737a98";
#[derive(Default)]
pub struct TracingFields<'a> {
fields: HashMap<&'a str, Field<'a>>,
}
enum Field<'a> {
String(String),
ValuableRef(ValuableRef<'a>),
}
type ValuableRef<'a> = &'a (dyn Valuable + Send + Sync);
impl<'a> Debug for TracingFields<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut f = f.debug_struct("TracingFields");
for (k, v) in self.fields.iter() {
let value = match v {
Field::String(s) => s.as_value(),
Field::ValuableRef(r) => r.as_value(),
};
f.field(k, &value as _);
}
f.finish()
}
}
impl<'a> TracingFields<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
fields: HashMap::with_capacity(capacity),
}
}
pub fn insert<V: Valuable + Send + Sync>(&mut self, key: &'a str, value: &'a V) {
self.fields.insert(key, Field::ValuableRef(value));
}
pub fn insert_as_string<V: Display + Sync>(&mut self, key: &'a str, value: &V) {
self.fields.insert(key, Field::String(value.to_string()));
}
pub fn insert_as_debug<V: Debug + Sync>(&mut self, key: &'a str, value: &V) {
self.fields.insert(key, Field::String(format!("{value:?}")));
}
pub fn remove_keys<'b>(&mut self, keys: impl IntoIterator<Item = &'b str>) {
for key in keys {
self.remove_by_key(key);
}
}
pub fn remove_by_key(&mut self, key: &str) {
self.fields.remove(key);
}
}
impl<'a> Valuable for TracingFields<'a> {
fn as_value(&self) -> Value<'_> {
Value::Structable(self)
}
fn visit(&self, visit: &mut dyn Visit) {
for (field, value) in self.fields.iter() {
let value_ref = match value {
Field::String(s) => s.as_value(),
Field::ValuableRef(r) => r.as_value(),
};
visit.visit_named_fields(&NamedValues::new(&[NamedField::new(field)], &[value_ref]));
}
}
}
impl<'a> Structable for TracingFields<'a> {
fn definition(&self) -> StructDef<'_> {
StructDef::new_dynamic(TRACING_FIELDS_STRUCTURE_NAME, Fields::Named(&[]))
}
}