1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::{error::Error as StdError, fmt};

/// The stupidest box error ever. It's not even Send.
///
/// It has `From` implementations for some libstd error types,
/// you can derive `From<E>` for your own error types
/// with [make_bxable!]
pub struct BX(Box<dyn StdError>);

/// A type alias where `E` defaults to `BX`.
pub type Result<T, E = BX> = std::result::Result<T, E>;

impl BX {
    /// Create a new `BX` from an `E`.
    pub fn from_err(e: impl StdError + 'static) -> Self {
        Self(e.into())
    }

    /// Create a new `BX` from a boxed `E`.
    pub fn from_boxed(e: Box<dyn StdError + 'static>) -> Self {
        Self(e)
    }

    /// Create a new `BX` from a String
    pub fn from_string(s: String) -> Self {
        Self(s.into())
    }
}

pub fn box_error(e: impl StdError + 'static) -> BX {
    BX::from_err(e)
}

/// Adds `bx() -> BX` to error types
pub trait BxForErrors {
    fn bx(self) -> BX;
}

impl<E: StdError + 'static> BxForErrors for E {
    fn bx(self) -> BX {
        BX::from_err(self)
    }
}

/// Adds `bx() -> Result<T, BX>` to result types
pub trait BxForResults<T> {
    fn bx(self) -> Result<T, BX>;
}

impl<T, E: StdError + 'static> BxForResults<T> for Result<T, E> {
    fn bx(self) -> Result<T, BX> {
        self.map_err(BX::from_err)
    }
}

impl fmt::Debug for BX {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Display for BX {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl StdError for BX {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        self.0.source()
    }
}

/// Implements `From<E>` for `BX` for your own type.
#[macro_export]
macro_rules! make_bxable {
    ($ty:ty) => {
        impl From<$ty> for $crate::BX {
            fn from(e: $ty) -> Self {
                $crate::BX::from_err(e)
            }
        }
    };
}

make_bxable!(std::io::Error);
make_bxable!(std::fmt::Error);
make_bxable!(std::str::Utf8Error);
make_bxable!(std::string::FromUtf8Error);
make_bxable!(std::string::FromUtf16Error);
make_bxable!(std::num::ParseIntError);
make_bxable!(std::num::ParseFloatError);
make_bxable!(std::num::TryFromIntError);
make_bxable!(std::array::TryFromSliceError);
make_bxable!(std::char::ParseCharError);
make_bxable!(std::net::AddrParseError);
make_bxable!(std::time::SystemTimeError);
make_bxable!(std::env::VarError);
make_bxable!(std::sync::mpsc::RecvError);
make_bxable!(std::sync::mpsc::TryRecvError);
make_bxable!(std::sync::mpsc::SendError<Box<dyn StdError + Send + Sync>>);
make_bxable!(std::sync::PoisonError<Box<dyn StdError + Send + Sync>>);

#[macro_export]
macro_rules! bail {
    ($err:expr) => {
        return Err($crate::BX::from_err($err));
    };
    ($fmt:expr, $($arg:tt)*) => {
        return Err($crate::BX::from_string(format!($fmt, $($arg)*)));
    };
}