use std::error::Error as StdError;
use std::fmt;
use redis::{ErrorKind as RedisErrorKind, RedisError};
pub type CheckoutResult<T> = Result<T, CheckoutError>;
pub type InitializationResult<T> = Result<T, InitializationError>;
#[derive(Debug)]
pub struct CheckoutError {
kind: CheckoutErrorKind,
cause: Option<Box<dyn StdError + Send + Sync>>,
}
impl CheckoutError {
pub(crate) fn new(kind: CheckoutErrorKind) -> Self {
Self { kind, cause: None }
}
pub(crate) fn with_cause<E: StdError + Send + Sync + 'static>(
kind: CheckoutErrorKind,
cause: E,
) -> Self {
Self {
kind,
cause: Some(Box::new(cause)),
}
}
pub fn kind(&self) -> CheckoutErrorKind {
self.kind
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CheckoutErrorKind {
NoConnection,
CheckoutTimeout,
QueueLimitReached,
NoPool,
TaskExecution,
}
impl fmt::Display for CheckoutError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref cause) = self.cause {
write!(f, "{}: {}", self.description(), cause)
} else {
f.write_str(self.description())
}
}
}
impl StdError for CheckoutError {
fn description(&self) -> &str {
match self.kind {
CheckoutErrorKind::NoConnection => "there are no connections available",
CheckoutErrorKind::CheckoutTimeout => {
"there was no connection to checkout available in time"
}
CheckoutErrorKind::QueueLimitReached => "the queue limit has been reached",
CheckoutErrorKind::NoPool => "there was no pool available",
CheckoutErrorKind::TaskExecution => "task execution failed",
}
}
fn cause(&self) -> Option<&dyn StdError> {
self.cause.as_ref().map(|cause| &**cause as &dyn StdError)
}
}
impl From<CheckoutError> for RedisError {
fn from(error: CheckoutError) -> Self {
(
RedisErrorKind::IoError,
"checkout failed",
error.to_string(),
)
.into()
}
}
#[derive(Debug)]
pub struct InitializationError {
message: Option<String>,
cause: Option<Box<dyn StdError + Send + Sync>>,
}
impl InitializationError {
pub fn new<T: Into<String>, E: StdError + Send + Sync + 'static>(
msg: T,
cause: Option<E>,
) -> Self {
Self {
message: Some(msg.into()),
cause: cause.map(|cause| Box::new(cause) as Box<dyn StdError + Send + Sync>),
}
}
pub fn message_only<T: Into<String>>(msg: T) -> Self {
Self {
message: Some(msg.into()),
cause: None,
}
}
pub fn cause_only<E: StdError + Send + Sync + 'static>(cause: E) -> Self {
Self {
message: None,
cause: Some(Box::new(cause)),
}
}
}
impl fmt::Display for InitializationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match (self.message.as_ref(), self.cause.as_ref()) {
(Some(msg), Some(cause)) => write!(f, "{}: {}", msg, cause),
(Some(msg), None) => write!(f, "{}", msg),
(None, Some(cause)) => write!(f, "{}: {}", self.description(), cause),
(None, None) => write!(f, "{}", self.description()),
}
}
}
impl StdError for InitializationError {
fn description(&self) -> &str {
"initialization failed"
}
fn cause(&self) -> Option<&dyn StdError> {
self.cause.as_ref().map(|cause| &**cause as &dyn StdError)
}
}