try_ops/
lib.rs

1//! Macro thats simulate try catch but use 'ops'
2//! To use this macro you should give a try block that
3//! return a Result with Box<dyn std::error:Error>;
4//! The ops block should be return the same type of try block if success
5//! ret_type is necessary because compile cannot define Ok type
6#[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}