1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

//! An error handling / bubbling macro to reduce error handling boilerplate.
//! 
//! For a given fallible expression (expression returning a result), such as:
//! 
//! ```no_run
//! # type E = ();
//! #
//! fn do_something() -> Result<(), E> {
//!     // ....
//! # Ok(())
//! }
//! ```
//! 
//! This can be used as follows:
//! 
//! ```no_run
//! #[macro_use]
//! extern crate log;
//! 
//! #[macro_use]
//! extern crate handle_error;
//! 
//! # type E = ();
//! #
//! # fn do_something() -> Result<(), E> {
//! #     unimplemented!()
//! # }
//! #
//! fn main() -> Result<(), E> {
//!   let v = handle_error!(do_something(), "Failed to do something");
//!   Ok(())
//! }
//! ```
//! ```no_run
//! #[macro_use]
//! extern crate log;
//! 
//! #[macro_use]
//! extern crate handle_error;
//! 
//! # type E = ();
//! #
//! # fn do_something() -> Result<(), E> {
//! #     unimplemented!()
//! # }
//! #
//! fn main() -> Result<(), E> {
//!   let v = retry_error!(3, do_something(), "Failed to do something");
//!   Ok(())
//! }
//! ```
//! 
//! Replacing the common patterns:
//! 
//! ```no_run
//! #[macro_use]
//! extern crate log;
//! 
//! #[macro_use]
//! extern crate handle_error;
//! 
//! # type E = ();
//! # fn do_something() -> Result<(), E> {
//! #     unimplemented!()
//! # }
//! #
//! // Match case where we care about the ok value
//! fn example_one() -> Result<(), E> {
//!   let v = match do_something() {
//!     Ok(v) => v,
//!     Err(e) => {
//!       error!("Failed to do something");
//!       return Err(e);
//!     }
//!   };
//! 
//!   Ok(())
//! }
//! 
//! // If let where we do not care about the ok value
//! fn example_two() -> Result<(), E> {
//!   if let Err(e) = do_something() {
//!     error!("Failed to do something");
//!     return Err(e);
//!   }
//! 
//!   Ok(())
//! }
//! 
//! # fn main() {}
//! ```


/// Log and propagate the error result from a given expression
///
/// This logs the provided message and exits the function scope on error, and returns
/// the unpacked Ok(value) on success.
#[macro_export]
macro_rules! handle_error {
    ($call:expr, $msg:expr, $($params:tt)*) => (
        match $call {
            Ok(v) => v,
            Err(e) => {
                error!($msg, $($params)*);
                return Err(e).into();
            },
        };
    );
    ($call:expr, $msg:expr) => (
        match $call {
            Ok(v) => v,
            Err(e) => {
                error!($msg);
                return Err(e).into();
            },
        };
    );
}

/// Retry a provided fallible function N times
///
/// This will optionally log a message, and returns the final error if all attempts fail
#[macro_export]
macro_rules! retry_error {
    ($retries:expr, $fallible:expr, $($params:tt)*) => (
        (|| {
            let mut i = 0;
            loop {
                match $fallible {
                    Ok(v) => break Ok(v),
                    Err(e) if i < $retries => {
                        i += 1;
                    },
                    Err(e) => {
                        error!($($params)*);
                        break Err(e)
                    },
                }
            }
        })()
    );
    ($retries:expr, $fallible:expr) => (
        (|| {
            let mut i = 0;
            loop {
                match $fallible {
                    Ok(v) => break Ok(v),
                    Err(e) if i < $retries => {
                        i += 1;
                    },
                    Err(e) => break Err(e),
                }
            }
        })()
    );
}