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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/// Given an existing type `E` implementing the [Error](std::error::Error) and [PartialEq] traits,
/// automatically provides an implementation for the following equality checks *and for the symmetric ones*:
///
/// * `E == Box<E>`, returning `true` if the boxed `E` equals the given one.
///
/// * `E == Box<dyn Error>`, returning `true` if the boxed error is of type `E` and actually equals the given one.
///
/// * `E == Result<_, E>`, returning `true` if the [Result] is [Err] and its wrapped error equals the given one.
///
/// * `E == Result<_, Box<E>>`, returning `true` if the [Result] is [Err] and the boxed error equals the given one.
///
/// * `E == Result<_, Box<dyn Error>>`, returning `true` if the [Result] is [Err], while the boxed error is of type `E` and equals the given one.
///
/// ```
/// use dyn_error::impl_err_equality;
/// use std::error::Error;
///
/// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// enum MyError {
/// First,
/// Second
/// }
///
/// impl std::fmt::Display for MyError {
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
/// write!(
/// f,
/// "{}",
/// match self {
/// Self::First => "First error".to_string(),
/// Self::Second => "Second error".to_string(),
/// }
/// )
/// }
/// }
///
/// impl Error for MyError {}
///
/// impl_err_equality!(MyError);
///
///
/// // Ensuring E == E
/// assert_eq!(MyError::First, MyError::First);
///
/// // Checking E == Box<E> (and vice versa)
/// assert_eq!(MyError::First, Box::new(MyError::First));
/// assert_eq!(Box::new(MyError::First), MyError::First);
///
/// // Checking E == Box<dyn Error> (and vice versa)
/// let dyn_box: Box<dyn Error> = Box::new(MyError::First);
/// assert_eq!(MyError::First, dyn_box);
/// assert_eq!(dyn_box, MyError::First);
///
/// // Checking E == Result<_, E> (and vice versa)
/// let result_with_err: Result<u8, MyError> = Err(MyError::First);
/// assert_eq!(MyError::First, result_with_err);
/// assert_eq!(result_with_err, MyError::First);
///
/// // Checking E == Result<_, Boxed<E>> (and vice versa)
/// let result_with_boxed_err: Result<u8, Box<MyError>> = Err(Box::new(MyError::First));
/// assert_eq!(MyError::First, result_with_boxed_err);
/// assert_eq!(result_with_boxed_err, MyError::First);
///
/// // Checking E == Result<_, Boxed<dyn Error>> (and vice versa)
/// let result_with_boxed_dyn_err: Result<u8, Box<dyn Error>> = Err(Box::new(MyError::First));
/// assert_eq!(MyError::First, result_with_boxed_dyn_err);
/// assert_eq!(result_with_boxed_dyn_err, MyError::First);
/// ```
#[macro_export]
macro_rules! impl_err_equality {
(
// The existing type for which the equality checks must be defined
$type: tt
) => {
impl PartialEq<Box<$type>> for $type {
fn eq(&self, other: &Box<$type>) -> bool {
*self == *other.as_ref()
}
}
impl PartialEq<$type> for Box<$type> {
fn eq(&self, other: &$type) -> bool {
*self.as_ref() == *other
}
}
impl PartialEq<Box<dyn std::error::Error>> for $type {
fn eq(&self, other: &Box<dyn std::error::Error>) -> bool {
match other.downcast_ref::<$type>() {
Some(cast_box) => *cast_box == *self,
None => false,
}
}
}
impl PartialEq<$type> for Box<dyn std::error::Error> {
fn eq(&self, other: &$type) -> bool {
match self.downcast_ref::<$type>() {
Some(cast_box) => *cast_box == *other,
None => false,
}
}
}
impl<T> PartialEq<Result<T, $type>> for $type {
fn eq(&self, other: &Result<T, $type>) -> bool {
match other {
Ok(_) => false,
Err(error) => *error == *self,
}
}
}
impl<T> PartialEq<$type> for Result<T, $type> {
fn eq(&self, other: &$type) -> bool {
match self {
Ok(_) => false,
Err(error) => *error == *other,
}
}
}
impl<T> PartialEq<Result<T, Box<$type>>> for $type {
fn eq(&self, other: &Result<T, Box<$type>>) -> bool {
match other {
Ok(_) => false,
Err(error_box) => *error_box == *self,
}
}
}
impl<T> PartialEq<$type> for Result<T, Box<$type>> {
fn eq(&self, other: &$type) -> bool {
match self {
Ok(_) => false,
Err(error_box) => *error_box == *other,
}
}
}
impl<T> PartialEq<Result<T, Box<dyn std::error::Error>>> for $type {
fn eq(&self, other: &Result<T, Box<dyn std::error::Error>>) -> bool {
match other {
Ok(_) => false,
Err(error_box) => *error_box == *self,
}
}
}
impl<T> PartialEq<$type> for Result<T, Box<dyn std::error::Error>> {
fn eq(&self, other: &$type) -> bool {
match self {
Ok(_) => false,
Err(error_box) => *error_box == *other,
}
}
}
};
}