loop_unwrap/
lib.rs

1//! # loop_unwrap
2//! Provides utility macros for unwrapping during loops.
3
4/// Works like `.unwrap`, if it's an Err or None, it calls `continue` on the loop.
5/// Prints an error message with `println!()` if provided.
6/// Loop Label can be provided in any order besides the Result/Option being the first argument.
7/// If loop label is proivded, the specified loop will be continued.
8/// # Examples
9/// ```
10/// loop {
11///         let input = "Not a number";
12///         let parsed_input: i32 = unwrap_continue!(input.parse()); //parse returns Err for this input
13///         break; //<-- never reached, since `continue` is called.
14///     }
15/// ```
16/// ```
17/// loop {
18///         let input = "Not a number";
19///         let parsed_input: i32 = unwrap_continue!(input.parse(), "Please Enter a Number!");
20///         // "Please Enter a Number!" is printed in console with a `println!()`
21///         break;
22///     }
23/// ```
24/// ```
25/// loop {
26///         let some_value: i32 = unwrap_continue!(Some(32), "Please Enter a Number!");
27///         assert_eq!(some_value, 32_i32)
28///     }
29/// ```
30/// ```
31/// 'main: loop {
32///         loop {
33///             let n =
34///                 unwrap_continue!("t".parse::<i32>(), "Couldn't parse, retrying main loop", 'main);
35///             break 'main; //<-- this line will never be reached, and main will go into an infinite loop
36///         }
37///         break; //<-- this line won't be reached, since 'main will be continued infinitely
38///     }
39/// ```
40#[macro_export]
41macro_rules! unwrap_continue {
42    ($x:expr) => {
43        match $x.to_option() {
44            Some(v) => v,
45            None => {
46                continue;
47            }
48        }
49    };
50    ($x:expr, $label:lifetime) => {
51        match $x.to_option() {
52            Some(v) => v,
53            None => {
54                continue $label;
55            }
56        }
57    };
58    ($x:expr, $label:lifetime, $err_msg:expr) => {
59        match $x.to_option() {
60            Some(v) => v,
61            None => {
62                println!("{}", $err_msg);
63                continue $label;
64            }
65        }
66    };
67    ($x:expr, $err_msg:expr) => {
68        match $x.to_option() {
69            Some(v) => v,
70            None => {
71                println!("{}", $err_msg);
72                continue;
73            }
74        }
75    };
76    ($x:expr, $err_msg:expr, $label:lifetime) => {
77        match $x.to_option() {
78            Some(v) => v,
79            None => {
80                println!("{}", $err_msg);
81                continue $label;
82            }
83        }
84    };
85
86
87
88}
89
90/// Works like `.unwrap`, if it's an Err or None, it calls `break` on the loop.
91/// Prints an error message with `println!()` if provided.
92/// Loop Label can be provided in any order besides the Result/Option being the first argument.
93/// If loop label is proivded, the specified loop will be break;-ed.
94/// # Examples
95/// ```
96/// loop {
97///         let input = "Not a number";
98///         let parsed_input: i32 = unwrap_break!(input.parse()); //parse returns Err for this input
99///     }
100/// println!("This line will be reached.");
101/// ```
102/// ```
103/// loop {
104///         let input = "Not a number";
105///         let parsed_input: i32 = unwrap_break!(input.parse(), "Please Enter a Number!");
106///         // "Please Enter a Number!" is printed in console with a `println!()`
107///         //loop breaks
108///     }
109/// ```
110/// ```
111/// loop {
112///         let some_value: i32 = unwrap_break!(Some(32), "Please Enter a Number!");
113///         assert_eq!(some_value, 32_i32)
114///         //no breakage here.
115///     }
116/// ```
117/// ```
118/// 'main: loop {
119///        loop {
120///            let n = unwrap_break!("t".parse::<i32>(), "Couldn't parse, exiting main loop", 'main);
121///            break; //<-- this line won't be reached.
122///        }
123///        println!("This line will never be reached, because 'main breaks.");
124///    }
125/// ```   
126#[macro_export]
127macro_rules! unwrap_break {
128    ($x:expr) => {
129        match $x.to_option() {
130            Some(v) => v,
131            None => {
132                break;
133            }
134        }
135    };
136    ($x:expr, $label:lifetime) => {
137        match $x.to_option() {
138            Some(v) => v,
139            None => {
140                break $label;
141            }
142        }
143    };
144    ($x:expr, $label:lifetime, $err_msg:expr) => {
145        match $x.to_option() {
146            Some(v) => v,
147            None => {
148                println!("{}", $err_msg);
149                break $label;
150            }
151        }
152    };
153    ($x:expr, $err_msg:expr) => {
154        match $x.to_option() {
155            Some(v) => v,
156            None => {
157                println!("{}", $err_msg);
158                break;
159            }
160        }
161    };
162    ($x:expr, $err_msg:expr, $label:lifetime) => {
163        match $x.to_option() {
164            Some(v) => v,
165            None => {
166                println!("{}", $err_msg);
167                break $label;
168            }
169        }
170    };
171}
172
173/// Works only on Result enum. If the value is Err(e), breaks the loop returning Err(e).
174/// Otherwise, it unwraps and the code continues.
175/// Supports loop labels.
176/// # Examples
177/// ```
178/// let value = loop {
179///        let s = "not a number";
180///        let n = unwrap_break_err!(s.parse::<i32>(), "Couldn't parse number."); // breaks with error value
181///        break Ok(n + 1); //<-- this line will never be reached since the macro breaks
182///    };
183///    assert_eq!(true, value.is_err());
184/// ```
185/// ```
186/// let result = 'main: loop {
187///         loop {
188///             let n = unwrap_break_err!("t".parse::<i32>(), 'main);
189///             break 'main Ok(100);
190///         }
191///     };
192///     assert_eq!(result.is_err(), true);
193/// ```    
194#[macro_export]
195macro_rules! unwrap_break_err {
196    ($x:expr) => {
197        match $x {
198            Ok(v) => v,
199            Err(e) => {
200                break Err(e);
201            }
202        }
203    };
204    ($x:expr, $label:lifetime) => {
205        match $x {
206            Ok(v) => v,
207            Err(e) => {
208                break $label Err(e);
209            }
210        }
211    };
212    ($x:expr, $label:lifetime, $err_msg:expr) => {
213        match $x {
214            Ok(v) => v,
215            Err(e) => {
216                println!("{}", $err_msg);
217                break $label Err(e);
218            }
219        }
220    };
221    ($x:expr, $err_msg:expr) => {
222        match $x {
223            Ok(v) => v,
224            Err(e) => {
225                println!("{}", $err_msg);
226                break Err(e);
227            }
228        }
229    };
230    ($x:expr, $err_msg:expr, $label:lifetime) => {
231        match $x {
232            Ok(v) => v,
233            Err(e) => {
234                println!("{}", $err_msg);
235                break $label Err(e);
236            }
237        }
238    };
239}
240
241pub trait ToOption<T> {
242    fn to_option(self) -> Option<T>;
243}
244
245impl<T> ToOption<T> for Option<T> {
246    fn to_option(self) -> Option<T> {
247        self
248    }
249}
250
251impl<T, U> ToOption<T> for Result<T, U> {
252    fn to_option(self) -> Option<T> {
253        match self {
254            Ok(v) => Some(v),
255            Err(_) => None,
256        }
257    }
258}