use miette::Diagnostic;
use nonempty::NonEmpty;
use std::borrow::Cow;
use std::fmt::Display;
pub trait Error: Diagnostic {
fn expected_type() -> Cow<'static, str>;
#[must_use]
fn details(type_name: impl Display) -> String {
format!(
"expected:\n {}\nbut found:\n {type_name}",
Self::expected_type()
)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct DeserializeErrors<T, E> {
pub recovered: Option<T>,
pub errors: E,
}
impl<T, E: Into<miette::Report>> DeserializeErrors<T, NonEmpty<E>> {
pub fn render_errors(self) -> DeserializeErrors<T, NonEmpty<String>> {
self.map_errors(|err| {
let report: miette::Report = err.into();
format!("{report:?}")
})
}
}
impl<T, E> DeserializeErrors<T, NonEmpty<E>> {
pub fn new(recovered: Option<T>, err: E) -> Self {
Self {
recovered,
errors: NonEmpty::new(err),
}
}
pub fn map<U, F: Fn(T) -> U>(self, f: F) -> DeserializeErrors<U, NonEmpty<E>> {
DeserializeErrors {
recovered: self.recovered.map(f),
errors: self.errors,
}
}
pub fn map_errors<U, F: Fn(E) -> U>(self, f: F) -> DeserializeErrors<T, NonEmpty<U>> {
DeserializeErrors {
recovered: self.recovered,
errors: self.errors.map(f),
}
}
pub fn recovered(recovered: T, err: E) -> Self {
Self {
recovered: Some(recovered),
errors: NonEmpty::new(err),
}
}
pub fn err(err: E) -> Self {
Self {
recovered: None,
errors: NonEmpty::new(err),
}
}
}