display_error_chain/
result_ext.rs1use std::{error::Error, fmt};
2
3use crate::DisplayErrorChain;
4
5pub trait ResultExt<T, E> {
7 #[track_caller]
11 fn unwrap_chain(self) -> T;
12
13 #[track_caller]
17 fn expect_chain(self, msg: &str) -> T;
18}
19
20impl<T, E: Error> ResultExt<T, E> for Result<T, E> {
21 #[inline]
22 #[track_caller]
23 fn unwrap_chain(self) -> T {
24 match self {
25 Ok(value) => value,
26 Err(e) => unwrap_failed(
27 "called `Result::unwrap_chain()` on an `Err` value",
28 &DisplayErrorChain::new(&e),
29 ),
30 }
31 }
32 #[inline]
33 #[track_caller]
34 fn expect_chain(self, msg: &str) -> T {
35 match self {
36 Ok(value) => value,
37 Err(e) => unwrap_failed(msg, &DisplayErrorChain::new(&e)),
38 }
39 }
40}
41
42#[inline(never)]
44#[cold]
45#[track_caller]
46fn unwrap_failed(msg: &str, error: &dyn fmt::Display) -> ! {
47 panic!("{}: {}", msg, error)
48}
49
50#[cfg(test)]
51mod test {
52 use super::ResultExt;
53
54 macro_rules! impl_error {
55 ($ty:ty, $display:expr, $source:expr) => {
56 impl ::std::fmt::Display for $ty {
57 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
58 write!(f, "{}", $display)
59 }
60 }
61
62 impl ::std::error::Error for $ty {
63 fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
64 $source
65 }
66 }
67 };
68 }
69
70 #[derive(Debug)]
72 struct TopLevel;
73 impl_error!(TopLevel, "top level", Some(&MidLevel));
74
75 #[derive(Debug)]
77 struct MidLevel;
78 impl_error!(MidLevel, "mid level", Some(&LowLevel));
79
80 #[derive(Debug)]
82 struct LowLevel;
83 impl_error!(LowLevel, "low level", None);
84
85 #[test]
86 #[should_panic(expected = "\
87 called `Result::unwrap_chain()` on an `Err` value: top level\n\
88Caused by:
89 -> mid level
90 -> low level")]
91 fn test_unwrap() {
92 Err::<(), _>(TopLevel).unwrap_chain();
93 }
94
95 #[test]
96 #[should_panic(expected = "\
97 Some message: top level\n\
98Caused by:
99 -> mid level
100 -> low level")]
101 fn test_expect() {
102 Err::<(), _>(TopLevel).expect_chain("Some message");
103 }
104}