use thiserror::Error;
use super::ErrorCode;
#[derive(Debug, Error, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum ConfErrReason {
#[error("core config")]
Core,
#[error("feature config error")]
Feature,
#[error("dynamic config error")]
Dynamic,
}
#[derive(Debug, Error, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub enum UvsReason {
#[error("validation error")]
ValidationError,
#[error("business logic error")]
BusinessError,
#[error("run rule error")]
RunRuleError,
#[error("not found error")]
NotFoundError,
#[error("permission error")]
PermissionError,
#[error("data error")]
DataError,
#[error("system error")]
SystemError,
#[error("network error")]
NetworkError,
#[error("resource error")]
ResourceError,
#[error("timeout error")]
TimeoutError,
#[error("configuration error << {0}")]
ConfigError(ConfErrReason),
#[error("external service error")]
ExternalError,
#[error("BUG :logic error")]
LogicError,
}
impl UvsReason {
pub fn core_conf() -> Self {
Self::ConfigError(ConfErrReason::Core)
}
pub fn feature_conf() -> Self {
Self::ConfigError(ConfErrReason::Feature)
}
pub fn dynamic_conf() -> Self {
Self::ConfigError(ConfErrReason::Dynamic)
}
pub fn validation_error() -> Self {
Self::ValidationError
}
pub fn business_error() -> Self {
Self::BusinessError
}
pub fn rule_error() -> Self {
Self::RunRuleError
}
pub fn not_found_error() -> Self {
Self::NotFoundError
}
pub fn permission_error() -> Self {
Self::PermissionError
}
pub fn data_error() -> Self {
Self::DataError
}
pub fn system_error() -> Self {
Self::SystemError
}
pub fn network_error() -> Self {
Self::NetworkError
}
pub fn resource_error() -> Self {
Self::ResourceError
}
pub fn timeout_error() -> Self {
Self::TimeoutError
}
pub fn external_error() -> Self {
Self::ExternalError
}
pub fn logic_error() -> Self {
Self::LogicError
}
}
pub trait UvsFrom: From<UvsReason> + Sized {
fn from_conf() -> Self {
Self::from(UvsReason::core_conf())
}
fn from_conf_reason(reason: ConfErrReason) -> Self {
Self::from(UvsReason::ConfigError(reason))
}
fn from_data() -> Self {
Self::from(UvsReason::data_error())
}
fn from_sys() -> Self {
Self::from(UvsReason::system_error())
}
fn from_biz() -> Self {
Self::from(UvsReason::business_error())
}
fn from_logic() -> Self {
Self::from(UvsReason::logic_error())
}
fn from_rule() -> Self {
Self::from(UvsReason::rule_error())
}
fn from_res() -> Self {
Self::from(UvsReason::resource_error())
}
fn from_net() -> Self {
Self::from(UvsReason::network_error())
}
fn from_timeout() -> Self {
Self::from(UvsReason::timeout_error())
}
fn from_validation() -> Self {
Self::from(UvsReason::validation_error())
}
fn from_not_found() -> Self {
Self::from(UvsReason::not_found_error())
}
fn from_permission() -> Self {
Self::from(UvsReason::permission_error())
}
fn from_external() -> Self {
Self::from(UvsReason::external_error())
}
}
impl<T> UvsFrom for T where T: From<UvsReason> {}
impl ErrorCode for UvsReason {
fn error_code(&self) -> i32 {
match self {
UvsReason::ValidationError => 100,
UvsReason::BusinessError => 101,
UvsReason::NotFoundError => 102,
UvsReason::PermissionError => 103,
UvsReason::LogicError => 104,
UvsReason::RunRuleError => 105,
UvsReason::DataError => 200,
UvsReason::SystemError => 201,
UvsReason::NetworkError => 202,
UvsReason::ResourceError => 203,
UvsReason::TimeoutError => 204,
UvsReason::ConfigError(_) => 300,
UvsReason::ExternalError => 301,
}
}
}
impl UvsReason {
pub fn is_retryable(&self) -> bool {
match self {
UvsReason::NetworkError => true,
UvsReason::TimeoutError => true,
UvsReason::ResourceError => true,
UvsReason::SystemError => true,
UvsReason::ExternalError => true,
UvsReason::ValidationError => false,
UvsReason::BusinessError => false,
UvsReason::RunRuleError => false,
UvsReason::NotFoundError => false,
UvsReason::PermissionError => false,
UvsReason::ConfigError(_) => false,
UvsReason::DataError => false,
UvsReason::LogicError => false,
}
}
pub fn is_high_severity(&self) -> bool {
match self {
UvsReason::SystemError => true,
UvsReason::ResourceError => true,
UvsReason::ConfigError(_) => true,
_ => false,
}
}
pub fn category_name(&self) -> &'static str {
match self {
UvsReason::ValidationError => "validation",
UvsReason::BusinessError => "business",
UvsReason::RunRuleError => "runrule",
UvsReason::NotFoundError => "not_found",
UvsReason::PermissionError => "permission",
UvsReason::DataError => "data",
UvsReason::SystemError => "system",
UvsReason::NetworkError => "network",
UvsReason::ResourceError => "resource",
UvsReason::TimeoutError => "timeout",
UvsReason::ConfigError(_) => "config",
UvsReason::ExternalError => "external",
UvsReason::LogicError => "logic",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_code_ranges() {
assert_eq!(UvsReason::validation_error().error_code(), 100);
assert_eq!(UvsReason::business_error().error_code(), 101);
assert_eq!(UvsReason::not_found_error().error_code(), 102);
assert_eq!(UvsReason::permission_error().error_code(), 103);
assert_eq!(UvsReason::data_error().error_code(), 200);
assert_eq!(UvsReason::system_error().error_code(), 201);
assert_eq!(UvsReason::network_error().error_code(), 202);
assert_eq!(UvsReason::resource_error().error_code(), 203);
assert_eq!(UvsReason::timeout_error().error_code(), 204);
assert_eq!(UvsReason::core_conf().error_code(), 300);
assert_eq!(UvsReason::external_error().error_code(), 301);
}
#[test]
fn test_retryable_errors() {
assert!(UvsReason::network_error().is_retryable());
assert!(UvsReason::timeout_error().is_retryable());
assert!(!UvsReason::validation_error().is_retryable());
assert!(!UvsReason::business_error().is_retryable());
}
#[test]
fn test_high_severity_errors() {
assert!(UvsReason::system_error().is_high_severity());
assert!(UvsReason::resource_error().is_high_severity());
assert!(!UvsReason::validation_error().is_high_severity());
assert!(!UvsReason::NotFoundError.is_high_severity());
}
#[test]
fn test_category_names() {
assert_eq!(UvsReason::network_error().category_name(), "network");
assert_eq!(UvsReason::business_error().category_name(), "business");
assert_eq!(UvsReason::core_conf().category_name(), "config");
}
#[test]
fn test_trait_implementations() {
let reason: UvsReason = <UvsReason as UvsFrom>::from_net();
assert_eq!(reason.error_code(), 202);
let reason: UvsReason = <UvsReason as UvsFrom>::from_validation();
assert_eq!(reason.error_code(), 100);
let reason: UvsReason = <UvsReason as UvsFrom>::from_external();
assert_eq!(reason.error_code(), 301);
}
}