#[macro_export]
macro_rules! define_kinds {
(
$(
$ident:ident = ($code:expr, $description:expr)
),* $(,)?
) => {
$(
#[doc = concat!("ErrorKind : ", stringify!($ident), " (", $code, ") - ", $description)]
#[allow(non_upper_case_globals)]
pub const $ident: cdumay_core::ErrorKind = cdumay_core::ErrorKind(stringify!($ident), $code, $description);
)*
};
}
#[macro_export]
macro_rules! define_errors {
(
$(
$name:ident = $kind_spec:tt
),* $(,)?
) => {
$(
define_errors!(@parse $name = $kind_spec);
)*
};
(@parse $name:ident = $kind:ident) => {
define_errors!(@impl $name, $kind, $kind.code(), $kind.description());
};
(@parse $name:ident = ($kind:ident, $code:expr)) => {
define_errors!(@impl $name, $kind, $code, $kind.description());
};
(@parse $name:ident = ($kind:ident, $code:expr, $message:expr)) => {
define_errors!(@impl $name, $kind, $code, $message);
};
(@impl $name:ident, $kind:ident, $code:expr, $message:expr) => {
#[doc = concat!("Error : ", stringify!($name), " (Kind: [`", stringify!($kind), "`])")]
#[derive(Debug, Clone)]
pub struct $name {
code: Option<u16>,
message: Option<String>,
details: Option<std::collections::BTreeMap<String, serde_value::Value>>,
}
impl $name {
pub fn new() -> Self {
Self {
code: None,
message: None,
details: None,
}
}
pub const kind: cdumay_core::ErrorKind = $kind;
#[inline]
pub fn code(&self) -> u16 {
self.code.unwrap_or($code)
}
pub fn with_code(mut self, code: u16) -> Self {
self.code = Some(code);
self
}
#[inline]
pub fn message(&self) -> String {
self.message.clone().unwrap_or($message.to_string())
}
pub fn with_message(mut self, message: String) -> Self {
self.message = Some(message);
self
}
#[inline]
pub fn details(&self) -> std::collections::BTreeMap<String, serde_value::Value> {
self.details.clone().unwrap_or_default()
}
pub fn with_details(mut self, details: std::collections::BTreeMap<String, serde_value::Value>) -> Self {
self.details = Some(details);
self
}
#[inline]
pub fn class(&self) -> String {
format!("{}::{}::{}", Self::kind.side(), Self::kind.name(), stringify!($name))
}
}
impl std::error::Error for $name {}
impl From<$name> for cdumay_core::Error {
fn from(err: $name) -> cdumay_core::Error {
cdumay_core::ErrorBuilder::new($name::kind, stringify!($name))
.with_code(err.code())
.with_message(err.message())
.with_details(err.details())
.build()
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} ({}): {}", self.class(), self.code(), self.message())
}
}
};
}