dyn_error/err_box/
fn_impl.rs

1use crate::ErrBoxCheckFailure;
2use std::error::Error;
3
4/// Tests whether the given [Result] is actually
5/// an [Err] with a [Box] containing an [Error] implementation
6/// equal to the *expected* instance:
7///
8/// * If the equality check succeeds, just returns [Ok] with
9///   a no-op `()` value;
10///
11/// * otherwise, returns [Err] - with a descriptive [ErrBoxCheckFailure].
12///
13/// ```
14/// use dyn_error::*;
15/// use std::fmt::Display;
16/// use std::error::Error;
17///
18/// #[derive(Debug, PartialEq, Eq)]
19/// struct MyErr(pub u8);
20///
21/// impl Display for MyErr {
22///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23///         write!(f, "Custom error: {}", self.0)
24///     }
25/// }
26///
27/// impl Error for MyErr {};
28///
29/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
30///     MyErr(90)
31/// ));
32///
33/// assert_eq!(
34///     check_err_box(
35///         result,
36///         MyErr(90)
37///     ),
38///     Ok(())
39/// );
40/// ```
41///
42/// In case of inequality, the function returns [Err]
43/// with [ErrBoxCheckFailure::NotEqual], containing the
44/// string representations of the two instances:
45///
46/// ```
47/// use dyn_error::*;
48/// use std::fmt::Display;
49/// use std::error::Error;
50///
51/// #[derive(Debug, PartialEq, Eq)]
52/// struct MyErr(pub u8);
53///
54/// impl Display for MyErr {
55///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56///         write!(f, "Custom error: {}", self.0)
57///     }
58/// }
59///
60/// impl Error for MyErr {};
61///
62/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
63///     MyErr(90)
64/// ));
65///
66/// assert_eq!(
67///     check_err_box(result, MyErr(7)),
68///     Err(ErrBoxCheckFailure::NotEqual {
69///         expected: "Custom error: 7".to_string(),
70///         actual: "Custom error: 90".to_string()
71///     })
72/// );
73/// ```
74///
75/// Of course, the check also fails if the boxed error and the expected error belong to unrelated types:
76///
77/// ```
78/// use dyn_error::*;
79/// use std::fmt::Display;
80/// use std::error::Error;
81///
82/// #[derive(Debug, PartialEq, Eq)]
83/// struct AlphaErr(pub u8);
84/// impl Display for AlphaErr {
85///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86///         write!(f, "Alpha error: {}", self.0)
87///     }
88/// }
89/// impl Error for AlphaErr {};
90///
91/// #[derive(Debug, PartialEq, Eq)]
92/// struct BetaErr(pub u8);
93/// impl Display for BetaErr {
94///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95///         write!(f, "Beta error: {}", self.0)
96///     }
97/// }
98/// impl Error for BetaErr {};
99///
100/// let result: Result<String, Box<dyn Error>> = Err(Box::new(
101///     BetaErr(90)
102/// ));
103///
104/// assert_eq!(
105///     check_err_box(result, AlphaErr(90)),
106///     Err(ErrBoxCheckFailure::DowncastFailed)
107/// );
108/// ```
109///
110/// Finally, the function fails also if the result is just [Ok]:
111///
112/// ```
113/// use dyn_error::*;
114/// use std::fmt::Display;
115/// use std::error::Error;
116///
117/// #[derive(Debug, PartialEq, Eq)]
118/// struct MyErr(pub u8);
119///
120/// impl Display for MyErr {
121///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122///         write!(f, "Custom error: {}", self.0)
123///     }
124/// }
125///
126/// impl Error for MyErr {};
127///
128/// let result: Result<String, Box<dyn Error>> = Ok("Dodo".to_string());
129///
130/// check_err_box(result, MyErr(7));
131/// ```
132pub fn check_err_box<T, E: Error + PartialEq<E> + 'static>(
133    result: Result<T, Box<dyn Error>>,
134    expected_err: E,
135) -> Result<(), ErrBoxCheckFailure> {
136    match result {
137        Ok(_) => Err(ErrBoxCheckFailure::ResultIsNotErr),
138
139        Err(ref e) => match e.downcast_ref::<E>() {
140            Some(boxed_err) => {
141                if expected_err == *boxed_err {
142                    Ok(())
143                } else {
144                    Err(ErrBoxCheckFailure::NotEqual {
145                        expected: expected_err.to_string(),
146                        actual: boxed_err.to_string(),
147                    })
148                }
149            }
150
151            None => Err(ErrBoxCheckFailure::DowncastFailed),
152        },
153    }
154}