dowhile_rs/
lib.rs

1#[macro_export]
2macro_rules! dowhile {
3    ($($label:lifetime:)? $body:block $(,)? $cond:expr) => ({
4        $($label:)? loop {
5            $body
6            if !$cond {
7                break $($label)?;
8            }
9        }
10    });
11    ($($label:lifetime:)? $body:block let $pattern:pat = $value:expr $(=> $cond:expr)?) => ({
12        $($label:)? loop {
13            $body
14            if let $pattern = $value {
15                $(if !$cond { 
16                    break; 
17                })?   
18            } else {
19                break $($label)?;
20            }
21        }
22    });
23    ($($label:lifetime:)? $body:block let $pattern:pat = $value:expr $(=> $cond:expr)?) => ({
24        $($label:)? loop {
25            $body
26            if let $pattern = $value {
27                $(if !$cond { 
28                    break; 
29                })?   
30            } else {
31                break $($label)?;
32            }
33        }
34    });
35    // Alternative syntax
36    ($cond:expr, $($label:lifetime:)? $body:block) => ({
37        $($label:)? loop {
38            $body
39            if !$cond {
40                break $($label)?;
41            }
42        }
43    });
44    (let $pattern:pat = $value:expr$ (=> $cond:expr)?, $($label:lifetime:)? $body:block) => ({
45        $($label:)? loop {
46            $body
47            if let $pattern = $value {
48                $(if !$cond {
49                    break;
50                })?   
51            } else {
52                break $($label)?;
53            }
54        }
55    });
56}
57
58#[cfg(test)]
59mod tests {
60    #[test]
61    fn nested_with_label() {
62        let mut v = vec![];
63        let mut x = 10;
64        dowhile!(x < 6, 'main: {
65            v.push(('x', x));
66            if x > 6 {
67                x = 0;
68                continue;
69            }
70            let mut y = x;
71            dowhile!({
72                v.push(('y', y));
73                if y > 3 {
74                    break 'main;
75                }
76                y += 1;
77            } y < x);
78            x += 1;
79        });
80        assert_eq!(v, vec![
81            ('x', 10), ('x', 0), ('y', 0), ('x', 1), ('y', 1), ('x', 2), 
82            ('y', 2), ('x', 3), ('y', 3), ('x', 4), ('y', 4)
83        ]);
84    }
85
86    #[test]
87    fn while_true() {
88        let mut x = 0;
89        dowhile!({
90            if x > 3 {
91                break;
92            }
93            x += 1;
94        }, true);
95        assert_eq!(x, 4);
96    }
97
98    #[test]
99    fn while_let() {
100        let mut x = Some(10);
101        let mut v = vec![];
102        dowhile!({
103            v.push(x);
104            x = Some(x.unwrap_or(0) - 1);
105        } let Some(8..) = x);
106        let vv = vec![Some(10), Some(9), Some(8)];
107        assert_eq!(v, vv);
108    }
109    
110    #[test]
111    fn while_let_val() {
112        let mut x = Some(10);
113        let mut v = vec![];
114        dowhile!({
115            v.push(x);
116            x = Some(x.unwrap_or(0) - 1);
117        } let Some(val) = x => val > 8);
118        let vv = vec![Some(10), Some(9)];
119        assert_eq!(v, vv);
120    }
121    
122    #[test]
123    fn while_let_alter() {
124        let mut x = Some(10);
125        let mut v = vec![];
126        dowhile!(let Some(val) = x => val > 8, {
127            v.push(x);
128            x = Some(x.unwrap_or(0) - 1);
129        });
130        let vv = vec![Some(10), Some(9)];
131        assert_eq!(v, vv);
132    }
133}