fabaccess-bffh/bffhd/error.rs
2024-12-13 15:32:21 +01:00

98 lines
2.1 KiB
Rust

use miette::{Diagnostic, Severity};
use std::error;
use std::fmt::{Display, Formatter};
use std::io;
use thiserror::Error;
pub trait Description {
const DESCRIPTION: Option<&'static str> = None;
const CODE: &'static str;
const HELP: Option<&'static str> = None;
const URL: Option<&'static str> = None;
}
pub fn wrap<D: Description>(error: Source) -> Error {
Error::new::<D>(error)
}
#[derive(Debug, Error, Diagnostic)]
pub enum Source {
#[error("io error occured")]
Io(
#[source]
#[from]
io::Error,
),
}
#[derive(Debug)]
pub struct Error {
description: Option<&'static str>,
code: &'static str,
severity: Option<Severity>,
help: Option<&'static str>,
url: Option<&'static str>,
source: Source,
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.source, f)
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(&self.source)
}
fn description(&self) -> &str {
if let Some(desc) = self.description {
desc
} else {
self.source.description()
}
}
}
impl Error {
pub fn new<D: Description>(source: Source) -> Self {
Self {
description: D::DESCRIPTION,
code: D::CODE,
severity: source.severity(),
help: D::HELP,
url: D::URL,
source,
}
}
}
impl miette::Diagnostic for Error {
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
Some(Box::new(self.code))
}
fn severity(&self) -> Option<Severity> {
self.severity
}
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.help.map(|r| {
let b: Box<dyn Display + 'a> = Box::new(r);
b
})
}
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
self.url.map(|r| {
let b: Box<dyn Display + 'a> = Box::new(r);
b
})
}
fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
Some(&self.source)
}
}