bitbazaar/errors/
macros.rs

1/// A macro for building `Report<AnyErr>` objects with string information easily.
2///
3/// `anyerr!()` is equivalent to `Report::new(AnyErr)`
4///
5/// `anyerr!("foo")` is equivalent to `Report::new(AnyErr).attach_printable("foo")`
6///
7/// `anyerr!("foo: {}", "bar")` is equivalent to `Report::new(AnyErr).attach_printable(format!("foo: {}", "bar"))`
8#[macro_export]
9macro_rules! anyerr {
10    () => {{
11        use $crate::errors::error_stack::Report;
12        use $crate::errors::AnyErr;
13
14        Report::new(AnyErr)
15    }};
16
17    ($str:expr) => {{
18        use $crate::errors::error_stack::Report;
19        use $crate::errors::AnyErr;
20
21        Report::new(AnyErr).attach_printable($str)
22    }};
23
24    ($str:expr, $($arg:expr),*) => {{
25        use $crate::errors::error_stack::Report;
26        use $crate::errors::AnyErr;
27
28        Report::new(AnyErr).attach_printable(format!($str, $($arg),*))
29    }};
30}
31
32/// A macro for building `Report<ArbitraryErrorStackErr>` objects with string context easily.
33///
34/// `err!(Err)` is equivalent to `Report::new(Err)`
35///
36/// `err!(Err, "foo")` is equivalent to `Report::new(Err).attach_printable("foo")`
37///
38/// `err!(Err, "foo: {}", "bar")` is equivalent to `Report::new(Err).attach_printable(format!("foo: {}", "bar"))`///
39#[macro_export]
40macro_rules! err {
41    ($err_variant:expr) => {{
42        use $crate::errors::error_stack::Report;
43
44        Report::new($err_variant)
45    }};
46
47    ($err_variant:expr, $str:expr) => {{
48        use $crate::errors::error_stack::Report;
49
50        Report::new($err_variant).attach_printable($str)
51    }};
52
53    ($err_variant:expr, $str:expr, $($arg:expr),*) => {{
54        use $crate::errors::error_stack::Report;
55
56        Report::new($err_variant).attach_printable(format!($str, $($arg),*))
57    }};
58}
59
60/// When working in a function that cannot return a result, use this to auto panic with the formatted error if something goes wrong.
61///
62/// Allows use of e.g. `?` in the block.
63#[macro_export]
64macro_rules! panic_on_err {
65    ($content:block) => {{
66        #[allow(clippy::redundant_closure_call)]
67        match ((|| $content)()) {
68            Ok(s) => s,
69            Err(e) => {
70                panic!("{:?}", e);
71            }
72        }
73    }};
74}
75
76/// When working in a function that cannot return a result, use this to auto panic with the formatted error if something goes wrong.
77///
78/// Allows use of e.g. `?` in the block.
79#[macro_export]
80macro_rules! panic_on_err_async {
81    ($content:block) => {{
82        match (async { $content }).await {
83            Ok(s) => s,
84            Err(e) => {
85                panic!("{:?}", e);
86            }
87        }
88    }};
89}
90
91#[cfg(test)]
92mod tests {
93    use futures::FutureExt;
94    use rstest::*;
95
96    use crate::prelude::*;
97
98    #[rstest]
99    fn panic_on_err() {
100        // Should work fine:
101        let result = panic_on_err!({
102            // ? syntax should work, test with something fallible:
103            let _ = Ok::<_, AnyErr>(1)?;
104            Ok::<_, AnyErr>(1)
105        });
106        assert_eq!(result, 1);
107
108        let should_err = std::panic::catch_unwind(|| {
109            panic_on_err!({
110                // ? syntax should work, test with something fallible:
111                let _ = Ok::<_, AnyErr>(1)?;
112                Err(anyerr!("foo"))
113            });
114        });
115        assert!(should_err.is_err());
116    }
117
118    #[rstest]
119    #[tokio::test]
120    async fn panic_on_err_async() {
121        let async_result = panic_on_err_async!({
122            // ? syntax should work, test with something fallible:
123            let _ = Ok::<_, AnyErr>(1)?;
124
125            tokio::time::sleep(std::time::Duration::from_nanos(1)).await;
126            Ok::<_, AnyErr>(1)
127        });
128        assert_eq!(async_result, 1);
129
130        let should_err = async {
131            panic_on_err_async!({
132                // ? syntax should work, test with something fallible:
133                let _ = Ok::<_, AnyErr>(1)?;
134
135                futures::future::ready(1).await;
136                Err(anyerr!("foo"))
137            });
138        };
139
140        assert!(should_err.catch_unwind().await.is_err());
141    }
142}