use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use std::{fmt::Display, io};
use crate::Decompose;
#[macro_export]
macro_rules! bterr {
($msg:literal $(,)?) => { $crate::Error::new(anyhow::anyhow!($msg)) };
($err:expr $(,)?) => { $crate::Error::new(anyhow::anyhow!($err)) };
($fmt:expr, $($arg:tt)*) => { $crate::Error::new(anyhow::anyhow!($fmt, $($arg)*)) };
}
#[macro_export]
macro_rules! btensure {
($cond:expr, $msg:literal $(,)?) => {
if !cond {
return Err($crate::bterr!($msg));
}
};
($cond:expr, $err:expr $(,)?) => {
if !$cond {
return Err($crate::bterr!($err));
}
};
($cond:expr, $fmt:expr, $($arg:tt)*) => {
if !cond {
return Err($crate::bterr!($msg, $($arg)*));
}
};
}
#[macro_export]
macro_rules! suppress_err_if_non_zero {
($count:expr, $result:expr) => {
match $result {
Ok(output) => output,
Err(err) => {
if $count > 0 {
error!("{err}");
return Ok($count);
} else {
return Err(err.into());
}
}
}
};
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct Error(anyhow::Error);
impl Error {
pub fn new(err: anyhow::Error) -> Self {
Self(err)
}
pub fn map<T>(result: ::anyhow::Result<T>) -> Result<T> {
result.map_err(Error::new)
}
pub fn downcast<E: std::error::Error + Send + Sync + 'static>(
self,
) -> std::result::Result<E, Self> {
self.0.downcast::<E>().map_err(Self::new)
}
pub fn context<C: Display + Send + Sync + 'static>(self, context: C) -> Self {
Self::new(self.0.context(context))
}
pub fn downcast_ref<E: Display + ::std::fmt::Debug + Send + Sync + 'static>(
&self,
) -> Option<&E> {
self.0.downcast_ref::<E>()
}
pub fn downcast_mut<E: Display + ::std::fmt::Debug + Send + Sync + 'static>(
&mut self,
) -> Option<&mut E> {
self.0.downcast_mut::<E>()
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl AsRef<anyhow::Error> for Error {
fn as_ref(&self) -> &anyhow::Error {
&self.0
}
}
impl AsMut<anyhow::Error> for Error {
fn as_mut(&mut self) -> &mut anyhow::Error {
&mut self.0
}
}
impl Decompose<anyhow::Error> for Error {
fn into_inner(self) -> anyhow::Error {
self.0
}
}
impl From<Error> for io::Error {
fn from(value: Error) -> Self {
let kind = value
.0
.downcast_ref::<io::ErrorKind>()
.copied()
.unwrap_or(io::ErrorKind::Other);
io::Error::new(kind, format!("{value}"))
}
}
impl<E: std::error::Error + Send + Sync + 'static> From<E> for Error {
fn from(value: E) -> Self {
Self::new(anyhow!(value))
}
}
#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Serialize, Deserialize, Hash)]
pub struct StringError(String);
impl StringError {
pub fn new(inner: String) -> StringError {
Self(inner)
}
pub fn take_value(self) -> String {
self.0
}
pub fn ref_value(&self) -> &String {
&self.0
}
pub fn mut_value(&mut self) -> &mut String {
&mut self.0
}
}
impl Display for StringError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl ::std::error::Error for StringError {}
impl From<String> for StringError {
fn from(value: String) -> Self {
Self::new(value)
}
}
impl From<StringError> for String {
fn from(value: StringError) -> Self {
value.take_value()
}
}
impl AsRef<String> for StringError {
fn as_ref(&self) -> &String {
self.ref_value()
}
}
impl AsMut<String> for StringError {
fn as_mut(&mut self) -> &mut String {
self.mut_value()
}
}
pub trait BtErr<T> {
fn bterr(self) -> Result<T>;
}
impl<T, E: ::std::error::Error + Send + Sync + 'static> BtErr<T> for ::std::result::Result<T, E> {
fn bterr(self) -> Result<T> {
self.map_err(|err| bterr!(err))
}
}
pub trait AnyhowErrorExt<T> {
fn bterr(self) -> Result<T>;
}
impl<T> AnyhowErrorExt<T> for anyhow::Result<T> {
fn bterr(self) -> Result<T> {
self.map_err(|err| bterr!(err))
}
}
pub trait IoErr<T> {
fn io_err(self) -> io::Result<T>;
}
impl<T> IoErr<T> for Result<T> {
fn io_err(self) -> io::Result<T> {
self.map_err(|err| err.into())
}
}
pub trait DisplayErr<T> {
fn display_err(self) -> Result<T>;
}
impl<T, E: Display> DisplayErr<T> for std::result::Result<T, E> {
fn display_err(self) -> Result<T> {
self.map_err(|err| bterr!("{err}"))
}
}
pub trait BoxInIoErr<T> {
fn box_err(self) -> std::result::Result<T, io::Error>;
}
impl<T, E: std::error::Error + Send + Sync + 'static> BoxInIoErr<T> for std::result::Result<T, E> {
fn box_err(self) -> std::result::Result<T, io::Error> {
self.map_err(|err| bterr!(err).into())
}
}