Skip to main content

cargo_intraconv/
error.rs

1//! Helper module providing some macros to print errors or unwrap values.
2//!
3//! This module exists because I could not find an error-handling crate that
4//! let me decide how to deal with errors in the following way:
5//!
6//! - Continue execution.
7//! - Exit with a code.
8//!
9//! While priting an error message in both cases.
10
11/// Unwraps the result in the first argument, printing the error and continuing
12/// the current loop if it is an `Err`.
13///
14/// Will add a `-- error: {error}` at the end of the given error text.
15#[macro_export]
16macro_rules! continue_error {
17    ($value:expr, $($arg:tt)*) => {
18        $crate::__error!(continue, $value, $($arg)*);
19    };
20}
21
22/// Unwraps the result in the first argument, printing the error and returning
23/// if it is an `Err`.
24///
25/// Will add a `-- error: {error}` at the end of the given error text.
26#[macro_export]
27macro_rules! return_error {
28    ($value:expr, $($arg:tt)*) => {
29        $crate::__error!(return, $value, $($arg)*);
30    };
31}
32
33/// Unwraps the result in the second argument, printing the error and exiting
34/// the current process with the given error code if it is an `Err`.
35///
36/// Will add a `-- error: {error}` at the end of the given error text.
37#[macro_export]
38macro_rules! code_error {
39    ($code: expr, $value:expr, $($arg:tt)*) => {
40        $crate::__error!(::std::process::exit($code), $value, $($arg)*);
41    };
42}
43
44/// Internl helper macro to avoid repeating pretty much the same code several
45/// times.
46///
47/// Will add a `-- error: {error}` at the end of the given error text.
48#[macro_export]
49macro_rules! __error {
50    ($out:expr, $value:expr, $($arg:tt)*) => {
51        match $value {
52            ::std::result::Result::Ok(v) => v,
53            ::std::result::Result::Err(e) => {
54                ::std::eprint!($($arg)*);
55                ::std::eprintln!(" -- error: {}", e);
56                $out;
57            },
58        }
59    };
60}
61
62#[cfg(test)]
63type TestResult = Result<usize, usize>;
64
65#[test]
66fn continue_error() {
67    let mut res = 0;
68    // Should exit on the second iteration else it will never break.
69    loop {
70        if res != 0 {
71            break;
72        }
73        res = continue_error!(TestResult::Ok(4), "");
74        assert_eq!(res, 4);
75    }
76
77    // Should always continue, never reaching the false.
78    for i in 0..10 {
79        continue_error!(TestResult::Err(i), "");
80        assert!(false, "Should never be reached");
81    }
82}
83
84#[test]
85fn return_error() {
86    fn early_return() {
87        return_error!(TestResult::Err(4), "");
88        assert!(false, "Should never be reached");
89    }
90
91    early_return();
92
93    let mut returned_early = true;
94    let mut not_early_return = || {
95        return_error!(TestResult::Ok(2), "");
96        returned_early = false;
97    };
98    not_early_return();
99
100    assert!(!returned_early, "Value should be false");
101}