grit_junk_drawer/lib.rs
1
2
3//MACRO chain_match!
4/// Recursively match one or more patterns, each with optional guard clauses,
5/// and resolve to the final expresion or statement if all matches succeed, else resolve to the previous default
6/// expression or statement
7///
8/// The syntax is as follows:
9/// ```ignore
10/// where (default) is literally typing out (default)
11/// where <DEFAULT_DEFINITION> = (default) <pattern>, (<expression>|<statement>);
12/// where <MATCH_DEFINITION> = <expression>, <pattern> (if <expression>)? =>
13/// where <FINAL_MATCH_DEFINITION> = <MATCH_DEFINITION> (<expression>|<statement>)
14///
15/// chain_match!(
16/// <DEFAULT_DEFINITION>
17/// [<DEFAULT_DEFINITION> | <MATCH_DEFINITION>]*
18/// <FINAL_MATCH_DEFINITION>
19/// )
20/// ```
21/// ### Examples
22/// ```rust
23/// use grit_junk_drawer::chain_match;
24///
25/// type Deep = Option<Result<Option<Result<u64,()>>,()>>;
26/// type Simple = Option<u64>;
27/// type Complex = Option<(bool, Option<bool>)>;
28///
29/// fn main() -> Result<(), String> {
30/// let my_deep: Deep = Some(Ok(Some(Ok(42))));
31/// let my_simple: Simple = Some(69);
32/// let my_complex: Complex = Some((true, Some(false)));
33///
34/// // expression on pass, return static on fail
35/// let my_deep_val = chain_match!(
36/// (default) _, return Err(format!("expected 42"));
37/// my_deep, Some(res_1) =>
38/// res_1, Ok(opt_2) =>
39/// opt_2, Some(res_2) =>
40/// res_2, Ok(val) if val == 42 => val
41/// );
42/// assert_eq!(my_deep_val, 42);
43///
44/// // expression on pass, return dynamic on fail
45/// let my_simple_val = chain_match!(
46/// (default) invalid, return Err(format!("expected 69, got {:?}", invalid));
47/// my_simple, Some(val) if val == 69 => val
48/// );
49/// assert_eq!(my_simple_val, 69);
50///
51/// // expression on pass, static expression on fail
52/// let my_simple_result = chain_match!(
53/// (default) _, Err(format!("expected 70"));
54/// my_simple, Some(val) if val == 70 => Ok(val)
55/// );
56/// assert_eq!(my_simple_result, Err(format!("expected 70")));
57///
58/// // expression on pass, dynamic expression on fail
59/// let my_simple_result = chain_match!(
60/// (default) invalid, Err(invalid);
61/// my_simple, Some(val) if val == 70 => Ok(val)
62/// );
63/// assert_eq!(my_simple_result, Err(Some(69)));
64///
65/// // change default path midway
66/// let my_complex_result = chain_match!(
67/// (default) _, Err(format!("First check false"));
68/// my_complex, Some((true, next_option)) =>
69/// (default) _, Err(format!("Second check false"));
70/// next_option, Some(true) => Ok(format!("Both checks pass"))
71/// );
72/// assert_eq!(my_complex_result, Err(format!("Second check false")));
73///
74/// // execute statement instead of resolving to expression
75/// let mut it_passed: Option<bool> = None;
76/// chain_match!(
77/// (default) _, it_passed = Some(false);
78/// my_simple, Some(val) if val == 69 => it_passed = Some(true)
79/// );
80/// assert_eq!(it_passed, Some(true));
81///
82/// // expression on fail, statement on pass
83/// let main_result = chain_match!(
84/// (default) _, Err(format!("Program failed"));
85/// my_simple, Some(val) if val == 69 => return Ok(())
86/// );
87///
88/// return main_result
89/// }
90/// ```
91#[macro_export]
92macro_rules! chain_match {
93 // Final Match: Fail Expression, Pass Expression
94 ((default) $fail_pat:pat, $fail_expr:expr; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $pass_expr:expr) => {
95 match $match_expr {
96 $pass_pat $( if $guard )? => $pass_expr,
97 $fail_pat => $fail_expr
98 }
99 };
100 // Final Match: Fail Expression, Pass Statement
101 ((default) $fail_pat:pat, $fail_expr:expr; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $pass_stmt:stmt) => {
102 match $match_expr {
103 $pass_pat $( if $guard )? => $pass_stmt,
104 $fail_pat => $fail_expr
105 }
106 };
107 // Final Match: Fail Statement, Pass Expression
108 ((default) $fail_pat:pat, $fail_stmt:stmt; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $pass_expr:expr) => {
109 match $match_expr {
110 $pass_pat $( if $guard )? => $pass_expr,
111 $fail_pat => $fail_stmt
112 }
113 };
114 // Final Match: Fail Statement, Pass Statement
115 ((default) $fail_pat:pat, $fail_stmt:stmt; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $pass_stmt:stmt) => {
116 match $match_expr {
117 $pass_pat $( if $guard )? => $pass_stmt,
118 $fail_pat => $fail_stmt
119 }
120 };
121 // Recursive Match: Fail Expression, New Fail Expression
122 ((default) $fail_pat:pat, $fail_expr:expr; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => (default) $new_fail_pat:pat, $new_fail_expr:expr; $($tail:tt)*) => {
123 match $match_expr {
124 $pass_pat $( if $guard )? => chain_match!((default) $new_fail_pat, $new_fail_expr; $($tail)*),
125 $fail_pat => $fail_expr
126 }
127 };
128 // Recursive Match: Fail Expression, New Fail Statement
129 ((default) $fail_pat:pat, $fail_expr:expr; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => (default) $new_fail_pat:pat, $new_fail_stmt:stmt; $($tail:tt)*) => {
130 match $match_expr {
131 $pass_pat $( if $guard )? => chain_match!((default) $new_fail_pat, $new_fail_stmt; $($tail)*),
132 $fail_pat => $fail_expr
133 }
134 };
135 // Recursive Match: Fail Expression, Same Fail Expression
136 ((default) $fail_pat:pat, $fail_expr:expr; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $($tail:tt)*) => {
137 match $match_expr {
138 $pass_pat $( if $guard )? => chain_match!((default) $fail_pat, $fail_expr; $($tail)*),
139 $fail_pat => $fail_expr
140 }
141 };
142 // Recursive Match: Fail Statement, New Fail Expression
143 ((default) $fail_pat:pat, $fail_stmt:stmt; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => (default) $new_fail_pat:pat, $new_fail_expr:expr; $($tail:tt)*) => {
144 match $match_expr {
145 $pass_pat $( if $guard )? => chain_match!((default) $new_fail_pat, $new_fail_expr; $($tail)*),
146 $fail_pat => $fail_stmt
147 }
148 };
149 // Recursive Match: Fail Statement, New Fail Statement
150 ((default) $fail_pat:pat, $fail_stmt:stmt; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => (default) $new_fail_pat:pat, $new_fail_stmt:stmt; $($tail:tt)*) => {
151 match $match_expr {
152 $pass_pat $( if $guard )? => chain_match!((default) $new_fail_pat, $new_fail_stmt; $($tail)*),
153 $fail_pat => $fail_stmt
154 }
155 };
156 // Recursive Match: Fail Statement, Same Fail Statement
157 ((default) $fail_pat:pat, $fail_stmt:stmt; $match_expr:expr, $pass_pat:pat $( if $guard:expr )? => $($tail:tt)*) => {
158 match $match_expr {
159 $pass_pat $( if $guard )? => chain_match!((default) $fail_pat, $fail_stmt; $($tail)*),
160 $fail_pat => $fail_stmt
161 }
162 };
163}