use std::fmt::Display;
use itertools::Itertools;
#[derive(Debug)]
pub enum ErrorKind {
MissingField(&'static str),
WrongType(&'static str),
}
impl Display for ErrorKind {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::MissingField(f) => write!(fmt, "missing field: {f}"),
Self::WrongType(t) => write!(fmt, "wrong type: expected {t}"),
}
}
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
path: Vec<&'static str>,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.kind)?;
Itertools::intersperse(self.path.iter().rev(), &" -> ").try_for_each(|e| write!(f, "{e}"))
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn path(&self) -> &[&'static str] {
self.path.as_slice()
}
}
impl From<ErrorKind> for Error {
fn from(value: ErrorKind) -> Self {
Self {
kind: value,
path: Vec::new(),
}
}
}
pub trait TagError {
fn tag(self, tag: &'static str) -> Self;
}
impl<T> TagError for Result<T, Error> {
fn tag(mut self, tag: &'static str) -> Self {
if let Err(e) = &mut self {
e.path.push(tag);
}
self
}
}
impl TagError for Error {
fn tag(mut self, tag: &'static str) -> Self {
self.path.push(tag);
self
}
}