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), } } })() ); }