use std::{ error::Error, fmt::{self, Debug}, }; use tracing::Level; use tracing_error::SpanTrace; #[derive(Debug)] pub struct OpaqueError { span_trace: SpanTrace, pub context: String, pub level: Level, kind: Option, } impl fmt::Display for OpaqueError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // optional: only print span trace if requested "{:#}" if f.alternate() { let mut vec = Vec::new(); self.span_trace.with_spans(|metadata, _fields| { vec.push(metadata.name()); true }); if vec.len() > 1 { write!(f, "trace = {}", vec.pop().unwrap())?; } vec.reverse(); for s in vec { write!(f, "::{}", s)?; } }; write!(f, " {}", self.context)?; Ok(()) } } impl Error for OpaqueError {} impl OpaqueError { pub fn create(context: &str) -> OpaqueError { Self { span_trace: SpanTrace::capture(), context: context.to_string(), level: Level::ERROR, kind: None, } } pub fn create_with_kind(context: &str, kind: &str) -> OpaqueError { Self { span_trace: SpanTrace::capture(), context: context.to_string(), level: Level::ERROR, kind: Some(kind.to_string()), } } pub fn print_span_trace(&self) -> FancyTrace { let mut vec: Vec<(&str, String)> = Vec::new(); self.span_trace.with_spans(|metadata, _fields| { vec.push((metadata.name(), _fields.into())); true }); let str = vec.iter().rfold(String::new(), |mut acc, x| { let first = acc.len() == 0; if !first { // TODO: should this code be hardcoded? acc.push_str("\x1b[2m:\x1b[0m"); } acc.push_str(x.0); if !x.1.is_empty() { acc.push_str("{"); acc.push_str(&x.1); acc.push_str("}"); } acc }); FancyTrace { str } } pub fn set_level(mut self, lvl: Level) -> Self { self.level = lvl; self } pub fn get_kind(&self) -> &str { match self.kind.as_ref() { Some(x) => &x, None => &self.context, } } } pub struct FancyTrace { str: String, } impl fmt::Display for FancyTrace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\x1b[2m{{{{\x1b[0m {} \x1b[2m}}}}\x1b[0m", self.str) } } impl From for OpaqueError { fn from(value: String) -> Self { Self { span_trace: SpanTrace::capture(), context: value, level: Level::ERROR, kind: None, } } } impl From<&str> for OpaqueError { fn from(value: &str) -> Self { Self { span_trace: SpanTrace::capture(), context: value.to_string(), level: Level::ERROR, kind: None, } } } impl From for OpaqueError { fn from(value: crate::packets::ParseErrorTrace) -> Self { Self { span_trace: value.context, context: format!("{:?}", value.inner), level: Level::ERROR, kind: None, } } }