flow_control/
lib.rs

1
2//! [`break`]: https://doc.rust-lang.org/std/keyword.break.html
3//! [`continue`]: https://doc.rust-lang.org/std/keyword.continue.html
4//! [`return`]: https://doc.rust-lang.org/std/keyword.return.html
5//!
6//! Declarative macros for common control-flow use cases such as [`break`], [`continue`], and [`return`].
7//!
8//! ---
9//!
10//! [`break_if!(...)`](crate::break_if)
11//!
12//! [`break`] from a loop if a given predicate evaluates to [`true`].
13//!
14//! Supports optionally providing a loop label to specify the loop from which to [`break`].
15//! ```text
16//! use flow_control::break_if;
17//!
18//! break_if!(predicate);
19//! break_if!(predicate, label);
20//! ```
21//!
22//! ---
23//!
24//! [`continue_if!(...)`](crate::continue_if)
25//!
26//! [`continue`] to the next iteration of a loop if a given predicate evaluates to [`true`].
27//!
28//! Supports optionally providing a loop label to specify the loop in which to [`continue`].
29//! ```text
30//! use flow_control::continue_if;
31//!
32//! continue_if!(predicate);
33//! continue_if!(predicate, label);
34//! ```
35//!
36//! ---
37//!
38//! [`return_if!(...)`](crate::return_if)
39//!
40//! [`return`] from a function if a given predicate evaluates to [`true`].
41//!
42//! Supports optionally providing a value to [`return`].
43//! ```text
44//! use flow_control::return_if;
45//!
46//! return_if!(predicate);
47//! return_if!(predicate, value);
48//! ```
49//!
50//! ---
51//!
52
53/// [`break`]: https://doc.rust-lang.org/std/keyword.break.html
54///
55/// [`break`] from a loop if a given predicate evaluates to [`true`].
56///
57/// Supports optionally providing a loop label to specify the loop from which to [`break`].
58///
59/// # Usage
60///
61/// [`break_if!`](crate::break_if)`(predicate)`
62///
63/// [`break_if!`](crate::break_if)`(predicate, label)`
64///
65/// # Examples
66///
67/// #### Predicate only
68/// ```
69/// use flow_control::break_if;
70///
71/// let mut v = Vec::new();
72/// for outer_n in 1..3 {
73///     for inner_n in 1..5 {
74///         break_if!(inner_n == 3);
75///         v.push((outer_n, inner_n));
76///     }
77/// }
78///
79/// assert_eq!(
80///     v,
81///     vec![
82///         (1, 1), (1, 2),
83///         (2, 1), (2, 2),
84///     ]
85/// );
86/// ```
87///
88/// #### Predicate and label
89/// ```
90/// use flow_control::break_if;
91///
92/// let mut v = Vec::new();
93/// 'outer: for outer_n in 1..3 {
94///     for inner_n in 1..5 {
95///         break_if!(inner_n == 3, 'outer);
96///         v.push((outer_n, inner_n));
97///     }
98/// }
99///
100/// assert_eq!(
101///     v,
102///     vec![(1, 1), (1, 2)],
103/// );
104/// ```
105#[macro_export]
106macro_rules! break_if {
107    ($predicate:expr $(,)?) => {
108        if $predicate {
109            break;
110        }
111    };
112    ($predicate:expr, $label:tt $(,)?) => {
113        if $predicate {
114            break $label;
115        }
116    };
117}
118
119/// [`continue`]: https://doc.rust-lang.org/std/keyword.continue.html
120///
121/// [`continue`] to the next iteration of a loop if a given predicate evaluates to [`true`].
122///
123/// Supports optionally providing a loop label to specify the loop in which to [`continue`].
124///
125/// # Usage
126///
127/// [`continue_if!`](crate::continue_if)`(predicate)`
128///
129/// [`continue_if!`](crate::continue_if)`(predicate, label)`
130///
131/// # Examples
132///
133/// #### Predicate only
134/// ```
135/// use flow_control::continue_if;
136///
137/// let mut v = Vec::new();
138/// for outer_n in 1..3 {
139///     for inner_n in 1..5 {
140///         continue_if!(inner_n == 3);
141///         v.push((outer_n, inner_n));
142///     }
143/// }
144///
145/// assert_eq!(
146///     v,
147///     vec![
148///         (1, 1), (1, 2), (1, 4),
149///         (2, 1), (2, 2), (2, 4),
150///     ]
151/// );
152/// ```
153///
154/// #### Predicate and label
155/// ```
156/// use flow_control::continue_if;
157///
158/// let mut v = Vec::new();
159/// 'outer: for outer_n in 1..3 {
160///     for inner_n in 1..5 {
161///         continue_if!(inner_n == 3, 'outer);
162///         v.push((outer_n, inner_n));
163///     }
164/// }
165///
166/// assert_eq!(
167///     v,
168///     vec![
169///         (1, 1), (1, 2),
170///         (2, 1), (2, 2),
171///     ]
172/// );
173/// ```
174#[macro_export]
175macro_rules! continue_if {
176    ($predicate:expr $(,)?) => {
177        if $predicate {
178            continue;
179        }
180    };
181    ($predicate:expr, $label:tt $(,)?) => {
182        if $predicate {
183            continue $label;
184        }
185    };
186}
187
188/// [`return`]: https://doc.rust-lang.org/std/keyword.return.html
189///
190/// [`return`] from a function if a given predicate evaluates to [`true`].
191///
192/// Supports optionally providing a value to [`return`].
193///
194/// # Usage
195///
196/// [`return_if!`](crate::return_if)`(predicate)`
197///
198/// [`return_if!`](crate::return_if)`(predicate, value)`
199///
200/// # Examples
201///
202/// #### Default return
203/// ```
204/// use flow_control::return_if;
205///
206/// let mut v = Vec::new();
207/// (|| {
208///     for n in 1..10 {
209///         return_if!(n == 5);
210///         v.push(n)
211///     }
212/// })();
213///
214/// assert_eq!(v, vec![1, 2, 3, 4]);
215/// ```
216///
217/// #### Return a specified value
218/// ```
219/// use flow_control::return_if;
220///
221/// let get_value = || {
222///     for n in 1..10 {
223///         return_if!(n == 5, "early return");
224///     }
225///     return "return after loop";
226/// };
227///
228/// assert_eq!(get_value(), "early return");
229/// ```
230#[macro_export]
231macro_rules! return_if {
232    ($predicate:expr $(,)?) => {
233        if $predicate {
234            return;
235        }
236    };
237    ($predicate:expr, $ret:expr $(,)?) => {
238        if $predicate {
239            return $ret;
240        }
241    };
242}