fallthrough/lib.rs
1//! This crate provides a [`fallthrough`] macro,
2//! which allows performing a pattern match with fallthrough through the arms,
3//! in the style of [C `switch`](https://en.cppreference.com/w/c/language/switch).
4#![forbid(unsafe_code)]
5#![warn(rust_2018_idioms, clippy::cargo, clippy::semicolon_if_nothing_returned)]
6
7/// Accepts a match scrutinee,
8/// followed by a comma-separated list of zero or more pattern match arms.
9/// All arms but the first must be preceded with a `'label: `. Only the first arm
10/// can access identifiers bound by the pattern match. Inside the match arms,
11/// calling `break 'label;` will jump to the label's corresponding match arm
12/// (you can only jump downwards). The list of arms can optionally be followed by a final
13/// trailing label, which can be used to jump out of the fallthrough entirely.
14///
15/// # Example
16///
17/// ```
18/// use fallthrough::fallthrough;
19///
20/// fn fall(scrutinee: u32) -> u32 {
21/// let mut ret: u32 = 0;
22///
23/// fallthrough!(scrutinee,
24/// val @ (0 | 63..) => ret = val + 7,
25/// 'one: 1 => ret += 8,
26/// 'two: 2 => ret += 9,
27/// 'three: 3 if true => { ret += 10; break 'end },
28/// 'four: 4 => ret = 42,
29/// 'five: 5 => { ret += 1; break 'seven },
30/// 'six: 6 => ret = 3,
31/// 'seven: _ => ret *= 2,
32/// 'end
33/// );
34/// ret
35/// }
36///
37/// fn main() {
38/// assert_eq!(fall(0), 34);
39/// assert_eq!(fall(1), 27);
40/// assert_eq!(fall(2), 19);
41/// assert_eq!(fall(3), 10);
42/// assert_eq!(fall(4), 86);
43/// assert_eq!(fall(5), 2);
44/// assert_eq!(fall(6), 6);
45/// assert_eq!(fall(7), 0);
46/// assert_eq!(fall(64), 98);
47/// }
48/// ```
49#[macro_export]
50macro_rules! fallthrough {
51 ($scrutinee:expr $(,)?) => {
52 match $scrutinee {}
53 };
54 ($scrutinee:expr, $first_pat:pat $(if $first_guard:expr)? => $first_body:expr $(, $label:lifetime $(: $pat:pat $(if $guard:expr)? => $body:expr)?)* $(,)?) => {
55 $crate::fallthrough_rec!{ (match $scrutinee {
56 $first_pat $(if $first_guard)? => $first_body,
57 $($($pat $(if $guard)? => break $label,)?)*
58 }), $($label $(: ($body))?),* }
59 };
60}
61
62#[macro_export]
63#[doc(hidden)]
64macro_rules! fallthrough_rec {
65 (($($acc:tt)*),) => {$($acc)*};
66 (($($acc:tt)*), $label:lifetime) => {
67 $label: {
68 $($acc)*
69 }
70 };
71 (($($acc:tt)*), $label:lifetime: ($($body:tt)*) $(,$($follow:tt)*)? ) => {
72
73 $crate::fallthrough_rec!{($label: {
74 $($acc)*
75 }
76 $($body)*
77 ), $($($follow)*)?}
78 };
79}