use std::error::Error;
use std::fmt::{Debug, Display};
#[macro_export]
macro_rules! bail {
($($args:tt)*) => {
return $crate::failure!($($args)*)
}
}
#[macro_export]
macro_rules! failure {
($($args:tt)*) => {
$crate::Failure(::std::fmt::format(::std::format_args!($($args)*))).err_boxed()
}
}
#[macro_export]
macro_rules! failure_raw {
($($args:tt)*) => {
$crate::Failure(::std::fmt::format(::std::format_args!($($args)*)))
}
}
pub struct Failure(pub String);
impl Failure {
#[inline]
pub fn boxed(self) -> Box<dyn Error> {
Box::new(self) as Box<dyn Error>
}
#[inline]
pub fn err_boxed<T, E: From<Box<dyn Error>>>(self) -> Result<T, E> {
Err(self.boxed().into())
}
#[inline]
pub fn err<T>(self) -> Result<T, Self> {
Err(self)
}
}
impl Error for Failure {}
impl Display for Failure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Debug for Failure {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.0, f)
}
}
#[cfg(test)]
#[test]
#[allow(
unreachable_code,
unused_variables // since result is used in unreachable code the compiler says it's unused
)]
fn tests() {
assert_eq!(Failure("a".into()).to_string(), "a".to_owned());
fn failure() -> Result<(), Failure> {
let result = "bad";
return Failure("test".to_owned()).err();
return Err(Failure("test".to_owned()));
return failure_raw!("{result}").err();
return Err(failure_raw!("{result}"));
Ok(())
}
failure().unwrap_err();
fn box_dyn_error() -> Result<(), Box<dyn Error>> {
let result = "bad";
return Failure("test".to_owned()).err_boxed();
return Err(Failure("test".to_owned()).boxed());
bail!("{result}");
return failure!("{result}");
return failure_raw!("{}", result).err_boxed();
return Err(failure_raw!("{result}").boxed());
Ok(())
}
box_dyn_error().unwrap_err();
}