easy_switch/
lib.rs

1#![no_std]
2
3//! A traditional C-style switch expression. In contrast to traditional `match` expressions, the
4//! [switch!](switch) macro will test against expressions, not patterns. The API of this crate is
5//! tiny, with just a single item.
6//!
7//! Internally, `switch!` just expands to a bunch of if-else expressions!
8//!
9//! # Example
10//!
11//! ```
12//! use easy_switch::switch;
13//!
14//! let num = 50;
15//! let case1 = 20;
16//! let case2 = 30;
17//! let matching = switch! { num;
18//!     case1 => "case1",
19//!     case2 => "case2",
20//!     25 + 25 => "unnamed case",
21//!     _ => "default case",
22//! };
23//! assert_eq!("unnamed case", matching);
24//! ```
25//!
26//! # Multiple Conditions
27//!
28//! Multiple conditions can be chained together with a comma.
29//! ```
30//! use easy_switch::switch;
31//!
32//! #[derive(PartialEq, Eq)]
33//! struct Example {
34//!     field: i32,
35//!     field2: i32,
36//! }
37//!
38//! impl Example {
39//!     pub fn new(field2: i32) -> Self {
40//!         Self {
41//!             field: 10,
42//!             field2,
43//!         }
44//!     }
45//! }
46//!
47//! let switchable = Example::new(10);
48//! let result = switch! { switchable;
49//!     Example::new(50), 50 == 50 => 50,
50//!     Example::new(20), 50 == 50, 20 == 20 => 20,
51//!     _ => 0,
52//! };
53//! assert_eq!(0, result);
54//! ```
55
56/// The macro used to emulate switch statements.
57///
58/// See the [crate level docs](../easy_switch/index.html) for more.
59///
60/// # Example
61///
62/// ```
63/// use easy_switch::switch;
64///
65/// let var = 30;
66/// let matched = switch! { var;
67///     15 + 15 => true,
68///     22 => {
69///         println!("22?");
70///         false
71///     },
72///     _ => false,
73/// };
74/// assert!(matched);
75#[macro_export]
76macro_rules! switch {
77    // Single case
78    ($input:expr; $first:expr$(, $($conditions:expr),*)? => $execute:expr$(,)?) => {
79        if $input == $first $(&& $($conditions)&&*)? { $execute }
80    };
81
82    // Single case with else
83    ($input:expr; $first:expr$(, $($conditions:expr),*)? => $execute:expr, _ => $execute_last:expr$(,)?) => {
84        if $input == $first $(&& $($conditions)&&*)? { $execute }
85        else { $execute_last }
86    };
87
88    // Multi-case
89    ($input:expr; $first:expr$(, $($conditions:expr),*)? => $execute:expr, $($rest:expr$(, $($conditions_rest:expr),*)? => $exec:expr),+$(,)?) => {
90        if $input == $first $(&& $($conditions)&&*)? { $execute }
91        $(else if $input == $rest $(&& $($conditions_rest)&&*)? { $exec })*
92    };
93
94    // Multi-case with else
95    ($input:expr; $first:expr$(, $($conditions:expr),*)? => $execute:expr, $($rest:expr$(, $($conditions_rest:expr),*)? => $exec:expr),+, _ => $execute_last:expr$(,)?) => {
96        if $input == $first $(&& $($conditions)&&*)? { $execute }
97        $(else if $input == $rest $(&& $($conditions_rest)&&*)? { $exec })*
98        else { $execute_last }
99    };
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn single_case() {
108        let x = 3;
109        switch! { x;
110            3 => (),
111        }
112    }
113
114    #[test]
115    fn single_case_with_else() {
116        let x = 3;
117        switch! { x;
118            3 => (),
119            _ => (),
120        }
121    }
122
123    #[test]
124    fn multi_case() {
125        let x = 3;
126        switch! { x;
127            3 => (),
128            3 => (),
129            3 => (),
130            3 => (),
131        }
132    }
133
134    #[test]
135    fn multi_case_with_else() {
136        let x = 3;
137        switch! { x;
138            3 => (),
139            3 => (),
140            3 => (),
141            3 => (),
142            _ => (),
143        }
144    }
145}