1#[macro_export]
7macro_rules! catch {
8 ($ret_type:ty => try $block:block $(ops $name:ident: $ty: ty $ops_block:block)+) => {
9 {
10 #[inline(always)]
11 fn handled() -> Result<$ret_type, Box<dyn std::error::Error>> $block
12 match handled() {
13 Ok(val) => val,
14 $(Err($name) if $name.is::<$ty>() => {
15 let $name = $name.downcast_ref::<$ty>().unwrap();
16 $ops_block
17 },)*
18 e => panic!("{:?}", e)
19 }
20 }
21 };
22 (try $block:block $(ops $name:ident: $ty: ty $ops_block:block)+) => {crate::catch!(() => try $block $(ops $name: $ty $ops_block )+ ) }
23}
24
25#[cfg(test)]
26mod test {
27 use super::*;
28 use core::fmt;
29 use std::{error::Error, fmt::Display, io};
30
31 #[derive(Debug)]
32 struct ErrorTests;
33
34 impl Display for ErrorTests {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(f, "work")
37 }
38 }
39
40 impl Error for ErrorTests {}
41
42 #[test]
43 fn ops_correct_type() {
44 catch!(() => try {
45 aux(true)?;
46 assert!(false);
47 Ok(())
48 } ops e: io::Error {
49 assert_eq!(e.kind(), io::ErrorKind::Other);
50 } ops _e: ErrorTests {
51 });
52 }
53
54 #[test]
55 fn ops_correct_type_without_inform_return() {
56 catch!(try {
57 aux(true)?;
58 assert!(false);
59 Ok(())
60 } ops e: io::Error {
61 assert_eq!(e.kind(), io::ErrorKind::Other);
62 } ops _e: ErrorTests {
63 });
64 }
65
66
67
68 #[test]
69 fn success() {
70 let result = catch!(() => try {
71 aux(false)?;
72 Ok(())
73 } ops e: io::Error {
74 assert_eq!(e.kind(), io::ErrorKind::Other);
75 } ops _e: ErrorTests {
76 assert!(false);
77 });
78 assert_eq!((), result)
79 }
80
81 #[test]
82 fn success_without_inform_return() {
83 let result = catch!(try {
84 aux(false)?;
85 Ok(())
86 } ops e: io::Error {
87 assert_eq!(e.kind(), io::ErrorKind::Other);
88 } ops _e: ErrorTests {
89 assert!(false);
90 });
91 assert_eq!((), result)
92 }
93
94 fn aux(is_error: bool) -> Result<(), Box<dyn Error>> {
95 if is_error {
96 return Err(Box::new(io::Error::new(io::ErrorKind::Other, "oh nooo")));
97 }
98 Ok(())
99 }
100}