early_returns/
lib.rs

1#![doc = include_str!("../README.md")]
2
3/// Either get the value from an Option type or return from the current function.
4/// A default return value can be provided.
5/// ```
6/// use early_returns::some_or_return;
7/// fn do_something_with_option(i: Option<i32>) {
8///     let i = some_or_return!(i);
9///     println!("{i}");
10/// }
11/// ```
12#[macro_export]
13macro_rules! some_or_return {
14    ($from:expr) => {{
15        if let Some(f) = $from {
16            f
17        } else {
18            return;
19        }
20    }};
21    ($from:expr, $default_result:expr) => {{
22        if let Some(f) = $from {
23            f
24        } else {
25            return $default_result;
26        }
27    }};
28}
29
30/// Either get the value from an Option type or break out of a loop. If a loop lifetime is
31/// specified, that loop will be exited, otherwise the immediate loop is exited.
32/// ```
33/// use early_returns::some_or_break;
34/// fn do_something_with_option(vals: &Vec<Option<i32>>) {
35///     for val in vals {
36///         let val = some_or_break!(val);
37///         println!("{}", val);
38///     }
39///
40///     'l: for val in vals {
41///         for i in 0..5 {
42///             let val = some_or_break!(val, 'l);
43///             println!("{}", val + i);
44///         }
45///     }
46/// }
47/// ```
48#[macro_export]
49macro_rules! some_or_break {
50    ($from:expr) => {{
51        if let Some(f) = $from {
52            f
53        } else {
54            break;
55        }
56    }};
57
58    ($from:expr, $lt:lifetime) => {{
59        if let Some(f) = $from {
60            f
61        } else {
62            break $lt;
63        }
64    }};
65}
66
67/// Either get the value from an Option type or continue in a loop. If a loop lifetime is specified,
68/// that loop will be "continued", otherwise the immediate loop is "continued".
69/// ```
70/// use early_returns::some_or_continue;
71/// fn do_something_with_option(vals: &Vec<Option<i32>>) {
72///     for val in vals {
73///         let val = some_or_continue!(val);
74///         println!("{}", val);
75///     }
76///
77///     'l: for val in vals {
78///         for i in 0..5 {
79///             let val = some_or_continue!(val, 'l);
80///             println!("{}", val + i);
81///         }
82///     }
83/// }
84/// ```
85#[macro_export]
86macro_rules! some_or_continue {
87    ($from:expr) => {{
88        if let Some(f) = $from {
89            f
90        } else {
91            continue;
92        }
93    }};
94
95    ($from:expr, $lt:lifetime) => {{
96        if let Some(f) = $from {
97            f
98        } else {
99            continue $lt;
100        }
101    }};
102}
103
104/// Either get the value from a Result type or return from the current function.
105/// A default return value can be provided.
106/// ```
107/// use early_returns::{ok_or_return, some_or_return};
108/// fn do_something_with_result(i: Result<i32, ()>) {
109///     let i = ok_or_return!(i);
110/// }
111/// ```
112#[macro_export]
113macro_rules! ok_or_return {
114    ($from:expr) => {{
115        if let Ok(f) = $from {
116            f
117        } else {
118            return;
119        }
120    }};
121
122    ($from:expr, $default_result:expr) => {{
123        if let Ok(f) = $from {
124            f
125        } else {
126            return $default_result;
127        }
128    }};
129}
130
131/// Either get the Ok value from a Result type or break out of a loop. If a loop lifetime is
132/// specified, that loop will be exited, otherwise the immediate loop is exited.
133/// ```
134/// use early_returns::ok_or_break;
135/// fn do_something_with_option(vals: &Vec<Result<i32, ()>>) {
136///     for val in vals {
137///         let val = ok_or_break!(val);
138///         println!("{}", val);
139///     }
140///
141///     'l: for val in vals {
142///         for i in 0..5 {
143///             let val = ok_or_break!(val, 'l);
144///             println!("{}", val + i);
145///         }
146///     }
147/// }
148/// ```
149#[macro_export]
150macro_rules! ok_or_break {
151    ($from:expr) => {{
152        if let Ok(f) = $from {
153            f
154        } else {
155            break;
156        }
157    }};
158    ($from:expr, $lt:lifetime) => {{
159        if let Ok(f) = $from {
160            f
161        } else {
162            break $lt;
163        }
164    }};
165}
166
167/// Either get the value from a Result type or continue in a loop. If a loop lifetime is specified,
168/// that loop will be "continued", otherwise the immediate loop is "continued".
169/// ```
170/// use early_returns::ok_or_continue;
171/// fn do_something_with_option(vals: &Vec<Result<i32, ()>>) {
172///     for val in vals {
173///         let val = ok_or_continue!(val);
174///         println!("{}", val);
175///     }
176///
177///     'l: for val in vals {
178///         for i in 0..5 {
179///             let val = ok_or_continue!(val, 'l);
180///             println!("{}", val + i);
181///         }
182///     }
183/// }
184/// ```
185#[macro_export]
186macro_rules! ok_or_continue {
187    ($from:expr) => {{
188        if let Ok(f) = $from {
189            f
190        } else {
191            continue;
192        }
193    }};
194    ($from:expr, $lt:lifetime) => {{
195        if let Ok(f) = $from {
196            f
197        } else {
198            continue $lt;
199        }
200    }};
201}
202
203#[cfg(test)]
204mod test {
205    struct Tester {
206        value: i32,
207    }
208
209    impl Tester {
210        fn new() -> Tester {
211            Tester { value: 0 }
212        }
213
214        fn increment_with_optional(&mut self, value: Option<i32>) {
215            let value = some_or_return!(value);
216            self.value += value;
217        }
218
219        fn increment_with_result(&mut self, value: Result<i32, ()>) {
220            let value = ok_or_return!(value);
221            self.value += value;
222        }
223
224        fn increment_with_optional_with_ref(&mut self, value: Option<&i32>) {
225            let value = some_or_return!(value);
226            self.value += value;
227        }
228
229        fn increment_with_result_with_ref(&mut self, value: Result<&i32, ()>) {
230            let value = ok_or_return!(value);
231            self.value += value;
232        }
233
234        fn increment_with_ref_to_optional(&mut self, value: &Option<i32>) {
235            let value = some_or_return!(value);
236            self.value += value;
237        }
238
239        fn increment_with_ref_to_result(&mut self, value: &Result<i32, ()>) {
240            let value = ok_or_return!(value);
241            self.value += value;
242        }
243
244        fn increment_with_optional_with_break(&mut self, values: Vec<Option<i32>>) {
245            for value in values {
246                let value = some_or_break!(value);
247                self.value += value;
248            }
249        }
250
251        fn increment_with_optional_with_break_with_lifetime(&mut self, values: Vec<Option<i32>>) {
252            'l: for value in values {
253                self.value += 1;
254                for _i in 0..1 {
255                    let value = some_or_break!(value, 'l);
256                    self.value += value;
257                }
258            }
259        }
260
261        fn increment_with_optional_with_continue(&mut self, values: Vec<Option<i32>>) {
262            for value in values {
263                let value = some_or_continue!(value);
264                self.value += value;
265            }
266        }
267
268        fn increment_with_optional_with_continue_with_lifetime(
269            &mut self,
270            values: Vec<Option<i32>>,
271        ) {
272            'l: for value in values {
273                self.value += 1;
274                for _i in 0..1 {
275                    let value = some_or_continue!(value, 'l);
276                    self.value += value;
277                }
278            }
279        }
280
281        fn increment_with_result_with_break(&mut self, values: Vec<Result<i32, ()>>) {
282            for value in values {
283                let value = ok_or_break!(value);
284                self.value += value;
285            }
286        }
287
288        fn increment_with_result_with_break_with_lifetime(&mut self, values: Vec<Result<i32, ()>>) {
289            'l: for value in values {
290                self.value += 1;
291                for _i in 0..1 {
292                    let value = ok_or_break!(value, 'l);
293                    self.value += value;
294                }
295            }
296        }
297
298        fn increment_with_result_with_continue(&mut self, values: Vec<Result<i32, ()>>) {
299            for value in values {
300                let value = ok_or_continue!(value);
301                self.value += value;
302            }
303        }
304
305        fn increment_with_result_with_continue_with_lifetime(
306            &mut self,
307            values: Vec<Result<i32, ()>>,
308        ) {
309            'l: for value in values {
310                self.value += 1;
311                for _i in 0..1 {
312                    let value = ok_or_continue!(value, 'l);
313                    self.value += value;
314                }
315            }
316        }
317
318        fn increment_with_optional_by_ref(
319            &mut self,
320            values: Option<i32>
321        ) {
322
323            let i: &i32 = some_or_return!(values.as_ref());
324            self.value += i;
325        }
326
327        fn increment_with_optional_from_fn_result<F: Fn() -> Option<i32>>(
328            &mut self,
329            value_getter: F
330        ) {
331
332            let i: i32 = some_or_return!(value_getter());
333            self.value += i;
334        }
335    }
336
337    #[test]
338    fn should_return_early_with_unengaged_optional() {
339        let mut tester = Tester::new();
340        tester.increment_with_optional(None);
341        assert_eq!(tester.value, 0);
342    }
343
344    #[test]
345    fn should_not_return_early_with_engaged_optional() {
346        let mut tester = Tester::new();
347        tester.increment_with_optional(Some(1));
348        assert_eq!(tester.value, 1);
349    }
350
351    #[test]
352    fn should_return_early_with_err() {
353        let mut tester = Tester::new();
354        tester.increment_with_result(Err(()));
355        assert_eq!(tester.value, 0);
356    }
357
358    #[test]
359    fn should_not_return_early_with_ok() {
360        let mut tester = Tester::new();
361        tester.increment_with_result(Ok(1));
362        assert_eq!(tester.value, 1);
363    }
364
365    #[test]
366    fn should_return_early_with_unengaged_optional_with_ref() {
367        let mut tester = Tester::new();
368        tester.increment_with_optional_with_ref(None);
369        assert_eq!(tester.value, 0);
370    }
371
372    #[test]
373    fn should_not_return_early_with_engaged_optional_with_ref() {
374        let mut tester = Tester::new();
375        tester.increment_with_optional_with_ref(Some(&1));
376        assert_eq!(tester.value, 1);
377    }
378
379    #[test]
380    fn should_return_early_with_err_with_ref() {
381        let mut tester = Tester::new();
382        tester.increment_with_result_with_ref(Err(()));
383        assert_eq!(tester.value, 0);
384    }
385
386    #[test]
387    fn should_not_return_early_with_ok_with_ref() {
388        let mut tester = Tester::new();
389        tester.increment_with_result_with_ref(Ok(&1));
390        assert_eq!(tester.value, 1);
391    }
392
393    #[test]
394    fn should_return_early_with_ref_to_unengaged_optional() {
395        let mut tester = Tester::new();
396        tester.increment_with_ref_to_optional(&None);
397        assert_eq!(tester.value, 0);
398    }
399
400    #[test]
401    fn should_not_return_early_with_ref_to_engaged_optional() {
402        let mut tester = Tester::new();
403        tester.increment_with_ref_to_optional(&Some(1));
404        assert_eq!(tester.value, 1);
405    }
406
407    #[test]
408    fn should_return_early_with_ref_to_err() {
409        let mut tester = Tester::new();
410        tester.increment_with_ref_to_result(&Err(()));
411        assert_eq!(tester.value, 0);
412    }
413
414    #[test]
415    fn should_not_return_early_with_ref_to_ok() {
416        let mut tester = Tester::new();
417        tester.increment_with_ref_to_result(&Ok(1));
418        assert_eq!(tester.value, 1);
419    }
420
421    #[test]
422    fn should_break_with_unengaged_optional() {
423        let mut tester = Tester::new();
424        tester.increment_with_optional_with_break(vec![None, Some(1)]);
425        assert_eq!(tester.value, 0);
426    }
427
428    #[test]
429    fn should_break_with_unengaged_optional_with_lifetime() {
430        let mut tester = Tester::new();
431        tester.increment_with_optional_with_break_with_lifetime(vec![None, Some(1)]);
432        assert_eq!(tester.value, 1);
433    }
434
435    #[test]
436    fn should_continue_with_unengaged_optional() {
437        let mut tester = Tester::new();
438        tester.increment_with_optional_with_continue(vec![None, Some(1)]);
439        assert_eq!(tester.value, 1);
440    }
441
442    #[test]
443    fn should_continue_with_unengaged_optional_with_lifetime() {
444        let mut tester = Tester::new();
445        tester.increment_with_optional_with_continue_with_lifetime(vec![None, Some(1)]);
446        assert_eq!(tester.value, 3);
447    }
448
449    #[test]
450    fn should_break_with_err_result() {
451        let mut tester = Tester::new();
452        tester.increment_with_result_with_break(vec![Err(()), Ok(1)]);
453        assert_eq!(tester.value, 0);
454    }
455
456    #[test]
457    fn should_break_with_err_result_with_lifetime() {
458        let mut tester = Tester::new();
459        tester.increment_with_result_with_break_with_lifetime(vec![Err(()), Ok(1)]);
460        assert_eq!(tester.value, 1);
461    }
462
463    #[test]
464    fn should_continue_with_err_result() {
465        let mut tester = Tester::new();
466        tester.increment_with_result_with_continue(vec![Err(()), Ok(1)]);
467        assert_eq!(tester.value, 1);
468    }
469
470    #[test]
471    fn should_continue_with_err_result_with_lifetime() {
472        let mut tester = Tester::new();
473        tester.increment_with_result_with_continue_with_lifetime(vec![Err(()), Ok(1)]);
474        assert_eq!(tester.value, 3);
475    }
476
477    #[test]
478    fn should_get_optional_from_reference() {
479        let mut tester = Tester::new();
480        tester.increment_with_optional_by_ref(Some(1));
481        assert_eq!(tester.value, 1);
482        tester.increment_with_optional_by_ref(None);
483        assert_eq!(tester.value, 1);
484    }
485
486    #[test]
487    fn should_get_optional_from_function_result() {
488        let mut tester = Tester::new();
489        tester.increment_with_optional_from_fn_result(|| Some(1));
490        assert_eq!(tester.value, 1);
491        tester.increment_with_optional_from_fn_result(|| None);
492        assert_eq!(tester.value, 1);
493        let a = 1;
494        tester.increment_with_optional_from_fn_result(|| Some(a));
495        assert_eq!(tester.value, 2);
496    }
497
498    #[derive(Debug, Eq, PartialEq)]
499    struct MeaningOfLifeAnd {
500        value: i32
501    }
502
503    fn try_some_or_return_with_default(val: Option<i32>) -> MeaningOfLifeAnd {
504        let val = some_or_return!(val, MeaningOfLifeAnd { value: 42 });
505        MeaningOfLifeAnd {
506            value: val + 42
507        }
508    }
509
510    #[test]
511    fn should_return_default_when_none() {
512        assert_eq!(try_some_or_return_with_default(Some(1)), MeaningOfLifeAnd { value: 43 });
513        assert_eq!(try_some_or_return_with_default(None), MeaningOfLifeAnd { value: 42 });
514    }
515
516    fn try_ok_or_return_with_default(val: Result<i32, ()>) -> MeaningOfLifeAnd {
517        let val = ok_or_return!(val, MeaningOfLifeAnd { value: 42 });
518        MeaningOfLifeAnd {
519            value: val + 42
520        }
521    }
522
523    #[test]
524    fn should_return_default_when_err() {
525        assert_eq!(try_ok_or_return_with_default(Ok(1)), MeaningOfLifeAnd { value: 43 });
526        assert_eq!(try_ok_or_return_with_default(Err(())), MeaningOfLifeAnd { value: 42 });
527    }
528}