use thiserror::Error;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Error)]
pub enum Error {
#[error("{0}")]
Msg(String),
#[error("{context}: {inner}")]
WithContext {
context: String,
inner: Box<dyn std::error::Error + Send + Sync + 'static>,
},
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error(transparent)]
Archive(#[from] easy_archive::ArchiveError),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[error(transparent)]
Join(#[from] tokio::task::JoinError),
}
impl Error {
pub fn msg(message: impl Into<String>) -> Self {
Error::Msg(message.into())
}
}
pub trait Context<T> {
fn context(self, context: impl std::fmt::Display) -> Result<T>;
fn with_context<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: std::fmt::Display;
}
impl<T, E> Context<T> for std::result::Result<T, E>
where
E: std::error::Error + Send + Sync + 'static,
{
fn context(self, context: impl std::fmt::Display) -> Result<T> {
self.map_err(|e| Error::WithContext {
context: context.to_string(),
inner: Box::new(e),
})
}
fn with_context<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: std::fmt::Display,
{
self.map_err(|e| Error::WithContext {
context: f().to_string(),
inner: Box::new(e),
})
}
}
impl<T> Context<T> for Option<T> {
fn context(self, context: impl std::fmt::Display) -> Result<T> {
self.ok_or_else(|| Error::msg(context.to_string()))
}
fn with_context<F, D>(self, f: F) -> Result<T>
where
F: FnOnce() -> D,
D: std::fmt::Display,
{
self.ok_or_else(|| Error::msg(f().to_string()))
}
}
macro_rules! err {
($($arg:tt)*) => {
$crate::error::Error::msg(format!($($arg)*))
};
}
macro_rules! bail {
($($arg:tt)*) => {
return Err($crate::error::Error::msg(format!($($arg)*)))
};
}
pub(crate) use bail;
pub(crate) use err;