use std::error::Error as StdError;
use std::fmt::{self, Display, Formatter};
use crate::crypto::{Error as CryptoError, ErrorKind as CryptoErrorKind};
use crate::storage::{Error as StorageError, ErrorKind as StorageErrorKind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorKind {
Backend,
Busy,
Custom,
Duplicate,
Encryption,
Input,
NotFound,
Unexpected,
Unsupported,
}
impl ErrorKind {
pub fn as_str(&self) -> &'static str {
match self {
Self::Backend => "Backend error",
Self::Busy => "Busy",
Self::Custom => "Custom error",
Self::Duplicate => "Duplicate",
Self::Encryption => "Encryption error",
Self::Input => "Input error",
Self::NotFound => "Not found",
Self::Unexpected => "Unexpected error",
Self::Unsupported => "Unsupported",
}
}
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug)]
pub struct Error {
pub(crate) kind: ErrorKind,
pub(crate) cause: Option<Box<dyn StdError + Send + Sync + 'static>>,
pub(crate) message: Option<String>,
}
impl Error {
pub(crate) fn from_msg<T: Into<String>>(kind: ErrorKind, msg: T) -> Self {
Self {
kind,
cause: None,
message: Some(msg.into()),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn message(&self) -> Option<&str> {
self.message.as_deref()
}
pub(crate) fn with_cause<T: Into<Box<dyn StdError + Send + Sync + 'static>>>(
mut self,
err: T,
) -> Self {
self.cause = Some(err.into());
self
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if let Some(msg) = self.message.as_ref() {
f.write_str(msg)?;
} else {
f.write_str(self.kind.as_str())?;
}
if let Some(cause) = self.cause.as_ref() {
write!(f, "\nCaused by: {}", cause)?;
}
Ok(())
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.cause
.as_ref()
.map(|err| &**err as &(dyn StdError + 'static))
}
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind && self.message == other.message
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self {
kind,
cause: None,
message: None,
}
}
}
impl From<CryptoError> for Error {
fn from(err: CryptoError) -> Self {
let kind = match err.kind() {
CryptoErrorKind::Custom => ErrorKind::Custom,
CryptoErrorKind::Encryption => ErrorKind::Encryption,
CryptoErrorKind::ExceededBuffer | CryptoErrorKind::Unexpected => ErrorKind::Unexpected,
CryptoErrorKind::Invalid
| CryptoErrorKind::InvalidKeyData
| CryptoErrorKind::InvalidNonce
| CryptoErrorKind::MissingSecretKey
| CryptoErrorKind::Usage => ErrorKind::Input,
CryptoErrorKind::Unsupported => ErrorKind::Unsupported,
};
Error::from_msg(kind, err.message())
}
}
impl From<StorageError> for Error {
fn from(err: StorageError) -> Self {
let (kind, cause, message) = err.into_parts();
let kind = match kind {
StorageErrorKind::Backend => ErrorKind::Backend,
StorageErrorKind::Busy => ErrorKind::Busy,
StorageErrorKind::Custom => ErrorKind::Custom,
StorageErrorKind::Duplicate => ErrorKind::Duplicate,
StorageErrorKind::Encryption => ErrorKind::Encryption,
StorageErrorKind::Input => ErrorKind::Input,
StorageErrorKind::NotFound => ErrorKind::NotFound,
StorageErrorKind::Unexpected => ErrorKind::Unexpected,
StorageErrorKind::Unsupported => ErrorKind::Unsupported,
};
Error {
kind,
cause,
message,
}
}
}
macro_rules! err_msg {
() => {
$crate::error::Error::from($crate::error::ErrorKind::Input)
};
($kind:ident) => {
$crate::error::Error::from($crate::error::ErrorKind::$kind)
};
($kind:ident, $($args:tt)+) => {
$crate::error::Error::from_msg($crate::error::ErrorKind::$kind, format!($($args)+))
};
($($args:tt)+) => {
$crate::error::Error::from_msg($crate::error::ErrorKind::Input, format!($($args)+))
};
}
macro_rules! err_map {
($($params:tt)*) => {
|err| err_msg!($($params)*).with_cause(err)
};
}