#![allow(unused_macros)]
use core::fmt;
use nats_types::DeliveredMessage;
use std::{
error::Error as StdError,
string::{String, ToString},
};
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
description: Option<String>,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
InvalidUriScheme,
UriParseFailure,
InvalidClientConfig,
IOError,
ConcurrencyFailure,
SubscriptionFailure,
Timeout,
Miscellaneous,
Regex,
}
#[macro_export]
macro_rules! err {
($variant:ident, $msg:expr) => {
$crate::error::Error::new(
$crate::error::ErrorKind::$variant,
Some($msg)
)
};
($variant:ident, $fmt:expr, $($arg:tt)+) => {
err!($variant, &format!($fmt, $($arg)+))
};
}
impl ErrorKind {
pub fn as_str(self) -> &'static str {
match self {
ErrorKind::InvalidUriScheme => "Invalid URI scheme",
ErrorKind::UriParseFailure => "URI parse failure",
ErrorKind::InvalidClientConfig => "Invalid client configuration",
ErrorKind::IOError => "I/O failure",
ErrorKind::ConcurrencyFailure => "Concurrency Failure",
ErrorKind::SubscriptionFailure => "Subscription Failure",
ErrorKind::Timeout => "Timeout expired",
ErrorKind::Miscellaneous => "Miscellaneous error",
ErrorKind::Regex => "Regular Expression pare failure",
}
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Error {
pub fn new(kind: ErrorKind, description: Option<&str>) -> Self {
Error {
kind,
description: description.map(|desc| desc.to_string()),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl From<url::ParseError> for Error {
fn from(source: url::ParseError) -> Error {
err!(UriParseFailure, "URI parse failure: {}", source)
}
}
impl From<std::io::Error> for Error {
fn from(source: std::io::Error) -> Error {
err!(IOError, "I/O error: {}", source)
}
}
impl From<(ErrorKind, &'static str)> for Error {
fn from((kind, description): (ErrorKind, &'static str)) -> Error {
Error {
kind,
description: Some(description.to_string()),
}
}
}
impl From<Box<dyn std::error::Error>> for Error {
fn from(source: Box<dyn std::error::Error>) -> Error {
err!(Miscellaneous, "Misc error: {}", source)
}
}
impl From<crossbeam_channel::SendError<Vec<u8>>> for Error {
fn from(source: crossbeam_channel::SendError<Vec<u8>>) -> Error {
err!(ConcurrencyFailure, "Concurrency error: {}", source)
}
}
impl From<crossbeam_channel::SendError<DeliveredMessage>> for Error {
fn from(source: crossbeam_channel::SendError<DeliveredMessage>) -> Error {
err!(ConcurrencyFailure, "Concurrency error: {}", source)
}
}
impl From<crossbeam_channel::RecvTimeoutError> for Error {
fn from(source: crossbeam_channel::RecvTimeoutError) -> Error {
err!(Timeout, "Timeout expired: {}", source)
}
}
impl From<regex::Error> for Error {
fn from(source: regex::Error) -> Error {
err!(Regex, "Regular expression parse failure: {}", source)
}
}
impl StdError for Error {
fn description(&self) -> &str {
if let Some(ref desc) = self.description {
desc
} else {
self.kind.as_str()
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.description {
Some(ref desc) => write!(f, "{}: {}", self.description(), desc),
None => write!(f, "{}", self.description()),
}
}
}