use std::{any::type_name_of_val, error::Error, fmt::{Debug, Display, Formatter}};
pub type DceResult<T> = Result<T, DceError>;
pub type DceVoid = DceResult<()>;
pub const OK_VOID: DceVoid = Ok(());
pub const SERVICE_UNAVAILABLE: isize = 503;
pub const SERVICE_UNAVAILABLE_MESSAGE: &str = "Service Unavailable";
#[derive(Debug)]
pub enum DceFaultBody {
Message(String),
Error(&'static str, Box<dyn Error + Send>),
}
impl Display for DceFaultBody {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Message(msg) => f.write_fmt(format_args!("{}", msg)),
Self::Error(ty, err) => f.write_fmt(format_args!("[{}] {}", ty, err)),
}
}
}
#[derive(Debug)]
pub struct DceError {
pub public: bool,
pub code: isize,
pub body: DceFaultBody,
}
impl DceError {
pub fn msg<T: ToString>(public: bool, code: isize, message: T) -> Self {
DceError { public, code, body: DceFaultBody::Message(message.to_string()) }
}
pub fn pub_msg<T: ToString>(code: isize, message: T) -> Self {
Self::msg(true, code, message)
}
pub fn pub_msg0<T: ToString>(message: T) -> Self {
Self::msg(true, -1, message)
}
pub fn priv_msg<T: ToString>(code: isize, message: T) -> Self {
Self::msg(false, code, message)
}
pub fn priv_msg0<T: ToString>(message: T) -> Self {
Self::msg(false, -1, message)
}
pub fn err<T: Error + Send + 'static>(public: bool, code: isize, error: T) -> Self {
DceError { public, code, body: DceFaultBody::Error(type_name_of_val(&error), Box::new(error)) }
}
pub fn pub_err<T: Error + Send + 'static>(code: isize, error: T) -> Self {
Self::err(true, code, error)
}
pub fn pub_err0<T: Error + Send + 'static>(error: T) -> Self {
Self::err(true, -1, error)
}
pub fn priv_err<T: Error + Send + 'static>(code: isize, error: T) -> Self {
Self::err(false, code, error)
}
pub fn priv_err0<T: Error + Send + 'static>(error: T) -> Self {
Self::err(false, -1, error)
}
}
impl <T: Error + Send + 'static> From<T> for DceError {
fn from(value: T) -> Self {
DceError::err(false, -1, value)
}
}
impl Display for DceError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let Self{public, code, body} = self;
let flag = if *public { "PUB" } else { "PRIV" };
f.write_fmt(format_args!("[{}] {}: {}", flag, code, body))
}
}