/*! Error handling and reporting. */ use http::uri::InvalidUri; use nom::error::ErrorKind; use serde::{Deserialize, Serialize, Serializer}; use std::fmt::Debug; use std::net::AddrParseError; use std::num::{ParseFloatError, ParseIntError}; use std::string::FromUtf8Error; use tokio::task::JoinError; use std::sync::PoisonError; /** The common error type for this application. */ #[derive(Serialize, Deserialize)] pub struct Error { msg: String, #[serde(skip)] trace: Option, trace_str: Option, } #[allow(dead_code)] fn ser_trace(_: &Option, _: S) -> Result where S: Serializer, { todoval() } impl Error { pub fn with_msg>(s: S) -> Self { Self { msg: s.into(), trace: None, trace_str: Some(fmt_backtrace(&backtrace::Backtrace::new())), } } } fn fmt_backtrace(trace: &backtrace::Backtrace) -> String { use std::io::Write; let mut buf = vec![]; let mut c1 = 0; 'outer: for fr in trace.frames() { for sy in fr.symbols() { let is_ours = match sy.filename() { None => false, Some(s) => { let s = s.to_str().unwrap(); s.contains("dev/daqbuffer/") || s.contains("/retrsbld/") } }; let name = match sy.name() { Some(k) => k.to_string(), _ => "[err]".into(), }; let filename = match sy.filename() { Some(k) => match k.to_str() { Some(k) => k, _ => "[err]", }, _ => "[err]", }; let lineno = match sy.lineno() { Some(k) => k, _ => 0, }; if is_ours { write!(&mut buf, "\n {}\n {} {}", name, filename, lineno).unwrap(); c1 += 1; if c1 >= 10 { break 'outer; } } } } String::from_utf8(buf).unwrap() } impl std::fmt::Debug for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { let trace_str = if let Some(trace) = &self.trace { fmt_backtrace(trace) } else if let Some(s) = &self.trace_str { s.into() } else { "NOTRACE".into() }; write!(fmt, "Error {}\nTrace:\n{}", self.msg, trace_str) } } impl std::fmt::Display for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Debug::fmt(self, fmt) } } impl std::error::Error for Error {} impl From for Error { fn from(k: String) -> Self { Self::with_msg(k) } } impl From<&str> for Error { fn from(k: &str) -> Self { Self::with_msg(k) } } impl From for Error { fn from(k: std::io::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: AddrParseError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: http::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: hyper::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: serde_json::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: async_channel::RecvError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: chrono::format::ParseError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: ParseIntError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: ParseFloatError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: FromUtf8Error) -> Self { Self::with_msg(k.to_string()) } } impl From> for Error { fn from(k: nom::Err) -> Self { Self::with_msg(format!("nom::Err {:?}", k)) } } impl nom::error::ParseError for Error { fn from_error_kind(_input: I, kind: ErrorKind) -> Self { Self::with_msg(format!("ParseError {:?}", kind)) } fn append(_input: I, kind: ErrorKind, other: Self) -> Self { Self::with_msg(format!("ParseError kind {:?} other {:?}", kind, other)) } } impl From for Error { fn from(k: JoinError) -> Self { Self::with_msg(format!("JoinError {:?}", k)) } } impl From> for Error { fn from(k: Box) -> Self { Self::with_msg(format!("bincode::ErrorKind {:?}", k)) } } impl From for Error { fn from(k: tokio_postgres::Error) -> Self { Self::with_msg(k.to_string()) } } impl From> for Error { fn from(k: async_channel::SendError) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: InvalidUri) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: serde_cbor::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: std::fmt::Error) -> Self { Self::with_msg(k.to_string()) } } impl From for Error { fn from(k: regex::Error) -> Self { Self::with_msg(k.to_string()) } } impl From> for Error { fn from(_: PoisonError) -> Self { Self::with_msg("PoisonError") } } pub fn todo() { todo!("TODO"); } pub fn todoval() -> T { todo!("TODO todoval") }