use crate::{epoch::Seconds, hexbytes::Bytes};
use rand::RngCore;
use serde::{de, ser, Serializer};
use std::fmt;
#[derive(Debug, PartialEq, Clone)]
pub enum TraceId {
#[doc(hidden)]
New(u64, [u8; 12]),
#[doc(hidden)]
Rendered(String),
}
impl TraceId {
pub fn new() -> Self {
let mut buf = [0; 12];
rand::thread_rng().fill_bytes(&mut buf);
TraceId::New(Seconds::now().trunc(), buf)
}
}
impl Default for TraceId {
fn default() -> Self {
TraceId::new()
}
}
impl fmt::Display for TraceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TraceId::New(seconds, bytes) => write!(f, "1-{:08x}-{:x}", seconds, Bytes(bytes)),
TraceId::Rendered(value) => write!(f, "{}", value),
}
}
}
struct TraceIdVisitor;
impl<'de> de::Visitor<'de> for TraceIdVisitor {
type Value = TraceId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string value")
}
fn visit_str<E>(self, value: &str) -> Result<TraceId, E>
where
E: de::Error,
{
Ok(TraceId::Rendered(value.into()))
}
}
impl ser::Serialize for TraceId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{}", self))
}
}
impl<'de> de::Deserialize<'de> for TraceId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
deserializer.deserialize_str(TraceIdVisitor)
}
}