use std::{
fmt::{self, Display},
io,
str::Utf8Error,
};
use thiserror::Error;
macro_rules! format_err {
($kind:path, $msg:expr) => {
crate::error::Error::new(
$kind,
&$msg.to_string()
)
};
($kind:path, $fmt:expr, $($arg:tt)+) => {
format_err!($kind, &format!($fmt, $($arg)+))
};
}
macro_rules! fail {
($kind:path, $msg:expr) => {
return Err(format_err!($kind, $msg).into())
};
($kind:path, $fmt:expr, $($arg:tt)+) => {
fail!($kind, &format!($fmt, $($arg)+))
};
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
msg: String,
}
impl Error {
pub fn new<S: ToString>(kind: ErrorKind, description: &S) -> Self {
Self {
kind,
msg: description.to_string(),
}
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", &self.kind, &self.msg)
}
}
impl std::error::Error for Error {}
#[derive(Copy, Clone, Debug, Error, Eq, PartialEq)]
#[non_exhaustive]
pub enum ErrorKind {
#[error("bad parameter")]
BadParam,
#[cfg(feature = "fix")]
#[cfg_attr(docsrs, doc(cfg(feature = "fix")))]
#[error("fix failed")]
Fix,
#[error("I/O operation failed")]
Io,
#[error("not found")]
NotFound,
#[error("unable to acquire filesystem lock")]
LockTimeout,
#[error("parse error")]
Parse,
#[error("registry")]
Registry,
#[error("git operation failed")]
Repo,
#[error("bad version")]
Version,
}
impl From<Utf8Error> for Error {
fn from(other: Utf8Error) -> Self {
format_err!(ErrorKind::Parse, &other)
}
}
#[cfg(feature = "fix")]
#[cfg_attr(docsrs, doc(cfg(feature = "fix")))]
impl From<cargo_edit::Error> for Error {
fn from(other: cargo_edit::Error) -> Self {
format_err!(ErrorKind::Fix, &other)
}
}
impl From<cargo_lock::Error> for Error {
fn from(other: cargo_lock::Error) -> Self {
format_err!(ErrorKind::Io, &other)
}
}
impl From<fmt::Error> for Error {
fn from(other: fmt::Error) -> Self {
format_err!(ErrorKind::Io, &other)
}
}
impl From<io::Error> for Error {
fn from(other: io::Error) -> Self {
format_err!(ErrorKind::Io, &other)
}
}
impl Error {
#[cfg(feature = "git")]
pub(crate) fn from_tame(err: tame_index::Error) -> Self {
use tame_index::utils::flock::LockError;
match err {
tame_index::Error::Lock(lock_err) => match &lock_err.source {
LockError::TimedOut | LockError::Contested => {
format_err!(ErrorKind::LockTimeout, "{}", lock_err)
}
_ => format_err!(ErrorKind::Io, "{}", lock_err),
},
other => format_err!(ErrorKind::Registry, "{}", other),
}
}
pub(crate) fn from_toml(other: toml::de::Error) -> Self {
format_err!(crate::ErrorKind::Parse, &other)
}
}