use std::backtrace::Backtrace;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, PartialEq)]
pub enum ErrorKind {
DoesNotExist,
NotACollection,
NotAStorage,
AccessDenied,
Io,
InvalidData,
InvalidInput,
ReadOnly,
CollectionNotEmpty,
Exists,
PreconditionFailed,
Unavailable,
Unsupported,
Uncategorised,
}
impl ErrorKind {
pub fn error<E>(self, source: E) -> Error
where
E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
Error {
kind: self,
source: Some(source.into()),
backtrace: Backtrace::capture(),
}
}
#[must_use]
const fn as_str(&self) -> &'static str {
match self {
ErrorKind::DoesNotExist => "resource does not exist",
ErrorKind::NotACollection => "resource exists, but is not a collection",
ErrorKind::NotAStorage => "resource exists, but is not a storage",
ErrorKind::AccessDenied => "access to the resource was denied",
ErrorKind::Io => "input/output error",
ErrorKind::InvalidData => "operation returned data, but it is not valid",
ErrorKind::InvalidInput => "input data is invalid",
ErrorKind::ReadOnly => "the resource is read-only",
ErrorKind::CollectionNotEmpty => "the collection is not empty",
ErrorKind::Exists => "resource already exists",
ErrorKind::PreconditionFailed => "a required condition was not met",
ErrorKind::Unavailable => "the operation is not possible on this instance",
ErrorKind::Unsupported => "the operation is not supported",
ErrorKind::Uncategorised => "uncategorised error",
}
}
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.write_str(self.as_str())
}
}
#[derive(Debug)]
pub struct Error {
pub(crate) kind: ErrorKind,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
backtrace: Backtrace,
}
impl Error {
#[must_use]
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn backtrace(&self) -> &Backtrace {
&self.backtrace
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Error {
kind,
source: None,
backtrace: Backtrace::capture(),
}
}
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
let kind = match value.kind() {
std::io::ErrorKind::NotFound => ErrorKind::DoesNotExist,
std::io::ErrorKind::PermissionDenied => ErrorKind::AccessDenied,
std::io::ErrorKind::AlreadyExists => ErrorKind::Exists,
std::io::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
std::io::ErrorKind::InvalidData => ErrorKind::InvalidData,
_ => ErrorKind::Io,
};
Error {
kind,
source: Some(value.into()),
backtrace: Backtrace::capture(),
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.source {
Some(ref s) => write!(fmt, "{}: {}", self.kind, s),
None => self.kind.fmt(fmt),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.source {
Some(e) => Some(e.as_ref()),
None => None,
}
}
}