use crate::value::keys::Keys;
use crate::value::span::Span;
use core::fmt::DebugStruct;
use serde::Deserialize;
use serde::Serialize;
#[derive(Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Tracer {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) span: Option<Span>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) segment: Option<Segment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) keys: Option<Keys>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, with = "crate::serde::bytes_as_base64_opt")]
pub(crate) raw: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Segment {
Builtin,
Field,
Raw,
Route,
Setter,
Static,
}
impl From<Segment> for Tracer {
fn from(value: Segment) -> Self {
Tracer::default().with_segment(value)
}
}
impl From<Span> for Tracer {
fn from(value: Span) -> Self {
Tracer::default().with_span(value)
}
}
impl From<Keys> for Tracer {
fn from(value: Keys) -> Self {
Tracer::default().with_keys(value)
}
}
impl core::fmt::Debug for Tracer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if self == &Tracer::default() {
return write!(f, "Tracer::default()");
}
let mut f = f.debug_struct("Tracer");
let u8l = |n| String::from_utf8_lossy(n).into_owned();
let raw = self.raw.as_ref().map(|r| u8l(r));
debug_field(&mut f, "source", self.source.as_ref());
debug_field(&mut f, "span", self.span.as_ref());
debug_field(&mut f, "segment", self.segment.as_ref());
debug_field(&mut f, "keys", self.keys.as_ref());
debug_field(&mut f, "raw", raw.as_ref());
f.finish()
}
}
fn debug_field<T: core::fmt::Debug>(f: &mut DebugStruct<'_, '_>, name: &str, t: Option<&T>) {
t.as_ref().map(|s| f.field(name, s));
}
impl Tracer {
pub fn with_source<T: Into<String>>(mut self, t: T) -> Self {
self.trace_source(t);
self
}
pub fn with_span<T: Into<Span>>(mut self, t: T) -> Self {
self.trace_span(t);
self
}
pub fn with_segment<T: Into<Segment>>(mut self, t: T) -> Self {
self.trace_segment(t);
self
}
pub fn with_keys<T: Into<Keys>>(mut self, t: T) -> Self {
self.trace_keys(t);
self
}
pub fn with_raw<T: Into<Vec<u8>>>(mut self, t: T) -> Self {
self.trace_raw(t);
self
}
pub fn source(&self) -> Option<&str> {
self.source.as_deref()
}
pub fn span(&self) -> Option<Span> {
self.span
}
pub fn segment(&self) -> Option<Segment> {
self.segment
}
pub fn keys(&self) -> Option<&Keys> {
self.keys.as_ref()
}
pub fn raw(&self) -> Option<&[u8]> {
self.raw.as_deref()
}
pub(crate) fn trace_source<T: Into<String>>(&mut self, t: T) {
if self.source.is_none() {
self.source = Some(t.into()).filter(|t| !t.is_empty());
}
}
pub(crate) fn trace_span<T: Into<Span>>(&mut self, t: T) {
if self.span.is_none() {
self.span = Some(t.into());
}
}
pub(crate) fn trace_segment<T: Into<Segment>>(&mut self, t: T) {
if self.segment.is_none() {
self.segment = Some(t.into());
}
}
pub fn trace_segment_if<T: Into<Segment>, U: Into<Segment>>(&mut self, t: T, u: U) {
if self.segment == Some(t.into()) {
self.segment = Some(u.into());
}
}
pub(crate) fn trace_keys<T: Into<Keys>>(&mut self, t: T) {
if self.keys.is_none() {
self.keys = Some(t.into()).filter(|t| !t.is_empty());
}
}
pub(crate) fn trace_raw<T: Into<Vec<u8>>>(&mut self, t: T) {
if self.raw.is_none() {
self.raw = Some(t.into()).filter(|t| !t.is_empty());
}
}
pub(crate) fn trace<T: Into<Tracer>>(&mut self, tracer: T) {
let tracer = tracer.into();
tracer.source.map(|t| self.trace_source(t));
tracer.span.map(|t| self.trace_span(t));
tracer.segment.map(|t| self.trace_segment(t));
tracer.keys.map(|t| self.trace_keys(t));
tracer.raw.map(|t| self.trace_raw(t));
}
pub(crate) fn is_empty(&self) -> bool {
self.source.is_none()
&& self.span.is_none()
&& self.segment.is_none()
&& self.keys.is_none()
&& self.raw.is_none()
}
}