use std::fmt::Display;
use thiserror::*;
#[derive(Error, Debug)]
#[error(transparent)]
pub struct Error(pub(crate) InternalError);
pub type Result<T> = std::result::Result<T, Error>;
impl<E> From<E> for Error
where
E: Into<InternalError>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
#[derive(Error, Debug)]
#[non_exhaustive]
#[doc(hidden)]
pub enum InternalError {
#[error(transparent)]
Fmt(#[from] std::fmt::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Regex(#[from] fancy_regex::Error),
#[error(transparent)]
FromUtf8(#[from] std::string::FromUtf8Error),
#[error(transparent)]
Utf8(#[from] std::str::Utf8Error),
#[error(transparent)]
Base64(#[from] base64::DecodeError),
#[error(transparent)]
ParseFloat(#[from] std::num::ParseFloatError),
#[error(transparent)]
ParseInt(#[from] std::num::ParseIntError),
#[error(transparent)]
FloatIsNan(#[from] ordered_float::FloatIsNan),
#[error("{0}")]
StringErr(#[from] StringWrap),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
#[error(transparent)]
Terminfo(#[from] terminfo::Error),
#[error(transparent)]
FileDescriptor(#[from] filedescriptor::Error),
#[error(transparent)]
BlobLease(#[from] wezterm_blob_leases::Error),
#[cfg(feature = "use_image")]
#[error(transparent)]
ImageError(#[from] image::ImageError),
#[error("{}", .context)]
Context {
context: String,
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
}
impl From<String> for InternalError {
fn from(s: String) -> Self {
InternalError::StringErr(StringWrap(s))
}
}
#[derive(Error, Debug)]
#[doc(hidden)]
#[error("{0}")]
pub struct StringWrap(pub String);
#[macro_export]
macro_rules! format_err {
($msg:literal $(,)?) => {
return $crate::error::Error::from($crate::error::StringWrap($msg.to_string()))
};
($err:expr $(,)?) => {
return $crate::error::Error::from($crate::error::StringWrap(format!($err)))
};
($fmt:expr, $($arg:tt)*) => {
return $crate::error::Error::from($crate::error::StringWrap(format!($fmt, $($arg)*)))
};
}
#[macro_export]
macro_rules! bail {
($msg:literal $(,)?) => {
return Err($crate::error::StringWrap($msg.to_string()).into())
};
($err:expr $(,)?) => {
return Err($crate::error::StringWrap(format!($err)).into())
};
($fmt:expr, $($arg:tt)*) => {
return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into())
};
}
#[macro_export]
macro_rules! ensure {
($cond:expr, $msg:literal $(,)?) => {
if !$cond {
return Err($crate::error::StringWrap(format!($msg)).into());
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return Err($crate::error::StringWrap(format!($err)).into());
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !$cond {
return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into());
}
};
}
pub trait Context<T, E> {
fn context<C>(self, context: C) -> Result<T>
where
C: Display + Send + Sync + 'static;
fn with_context<C, F>(self, f: F) -> Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C;
}
impl<T, E> Context<T, E> for std::result::Result<T, E>
where
E: std::error::Error + Send + Sync + 'static,
{
fn context<C>(self, context: C) -> Result<T>
where
C: Display + Send + Sync + 'static,
{
self.map_err(|error| {
Error(InternalError::Context {
context: context.to_string(),
source: Box::new(error),
})
})
}
fn with_context<C, F>(self, context: F) -> Result<T>
where
C: Display + Send + Sync + 'static,
F: FnOnce() -> C,
{
self.map_err(|error| {
Error(InternalError::Context {
context: context().to_string(),
source: Box::new(error),
})
})
}
}