1#[macro_export]
2macro_rules! regexm {
3 (
4 match $str:tt {captures($pattern:expr) => |$caps:ident| $expr:expr, $($rest:tt)*}
5 ) => {
6 $crate::__regexm! {
7 tokens = [$($rest)*],
8 str = $str,
9 first_pattern = $pattern,
10 first_expr = {
11 let closure = |$caps: regex::Captures| $expr;
12 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
13 },
14 result = unknown,
15 }
16 };
17
18 (
19 match $str:tt {captures($pattern:expr) => |$caps:ident| $expr:block $($rest:tt)*}
20 ) => {
21 $crate::__regexm! {
22 tokens = [$($rest)*],
23 str = $str,
24 first_pattern = $pattern,
25 first_expr = {
26 let closure = |$caps: regex::Captures| $expr;
27 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
28 },
29 result = unknown,
30 }
31 };
32
33 (
34 match $str:tt {$pattern:expr => $expr:expr, $($rest:tt)*}
35 ) => {
36 $crate::__regexm! {
37 tokens = [$($rest)*],
38 str = $str,
39 first_pattern = $pattern,
40 first_expr = $expr,
41 result = unknown,
42 }
43 };
44
45 (
46 match $str:tt {$pattern:expr => $expr:block $($rest:tt)*}
47 ) => {
48 $crate::__regexm! {
49 tokens = [$($rest)*],
50 str = $str,
51 first_pattern = $pattern,
52 first_expr = $expr,
53 result = unknown,
54 }
55 };
56}
57
58#[macro_export]
59#[doc(hidden)]
60macro_rules! __regexm {
61 (
62 tokens = [captures($default:pat) => |$caps:ident| $default_expr:expr$(,)?],
63 str = $str:expr,
64 first_pattern = $first_pattern:expr,
65 first_expr = $first_expr:expr,
66 result = [$($result:tt)*],
67 ) => {
68 $($result)* else {
69 let closure = |$caps: regex::Captures| $default_expr;
70 closure(regex::Regex::new($default).unwrap().captures($str).unwrap())
71 };
72 };
73
74 (
75 tokens = [captures($default:pat) => |$caps:ident| $default_expr:block$(,)?],
76 str = $str:expr,
77 first_pattern = $first_pattern:expr,
78 first_expr = $first_expr:expr,
79 result = [$($result:tt)*],
80 ) => {
81 $($result)* else {
82 let closure = |$caps: regex::Captures| $default_expr;
83 closure(regex::Regex::new($default).unwrap().captures($str).unwrap())
84 };
85 };
86
87 (
88 tokens = [$default:pat => $default_expr:expr$(,)?],
89 str = $str:expr,
90 first_pattern = $first_pattern:expr,
91 first_expr = $first_expr:expr,
92 result = [$($result:tt)*],
93 ) => {
94 $($result)* else {$default_expr};
95 };
96
97 (
98 tokens = [$default:pat => $default_expr:block$(,)?],
99 str = $str:expr,
100 first_pattern = $first_pattern:expr,
101 first_expr = $first_expr:expr,
102 result = [$($result:tt)*],
103 ) => {
104 $($result)* else {$default_expr};
105 };
106
107 (
108 tokens = [],
109 str = $str:expr,
110 first_pattern = $first_pattern:expr,
111 first_expr = $first_expr:expr,
112 result = [$($result:tt)*],
113 ) => {
114 $($result)*
115 };
116
117 (
118 tokens = [captures($default:pat) => |$caps:ident| $default_expr:expr$(,)?],
119 str = $str:expr,
120 first_pattern = $first_pattern:expr,
121 first_expr = $first_expr:expr,
122 result = unknown,
123 ) => {
124 if regex::Regex::new($first_pattern).unwrap().is_match($str) {
125 $first_expr
126 } else {
127 let closure = |$caps: regex::Captures| $default_expr;
128 closure(regex::Regex::new($default).unwrap().captures($str).unwrap())
129 };
130 };
131
132 (
133 tokens = [captures($default:pat) => |$caps:ident| $default_expr:block$(,)?],
134 str = $str:expr,
135 first_pattern = $first_pattern:expr,
136 first_expr = $first_expr:expr,
137 result = unknown,
138 ) => {
139 if regex::Regex::new($first_pattern).unwrap().is_match($str) {
140 $first_expr
141 } else {
142 let closure = |$caps: regex::Captures| $default_expr;
143 closure(regex::Regex::new($default).unwrap().captures($str).unwrap())
144 };
145 };
146
147 (
148 tokens = [$default:pat => $default_expr:expr$(,)?],
149 str = $str:expr,
150 first_pattern = $first_pattern:expr,
151 first_expr = $first_expr:expr,
152 result = unknown,
153 ) => {
154 if regex::Regex::new($first_pattern).unwrap().is_match($str) {
155 $first_expr
156 } else {$default_expr};
157 };
158
159 (
160 tokens = [$default:pat => $default_expr:block$(,)?],
161 str = $str:expr,
162 first_pattern = $first_pattern:expr,
163 first_token = $first_tokens:expr,
164 result = unknown,
165 ) => {
166 if regex::Regex::new($first_pattern).unwrap().is_match($str) {
167 $first_tokens
168 } else {$default_expr};
169 };
170
171 (
172 tokens = [captures($pattern:expr) => |$caps:ident| $expr:expr, $($rest:tt)*],
173 str = $str:expr,
174 first_pattern = $first_pattern:expr,
175 first_expr = $first_expr:expr,
176 result = unknown,
177 ) => {
178 $crate::__regexm! {
179 tokens = [$($rest)*],
180 str = $str,
181 first_pattern = $first_pattern,
182 first_expr = $first_expr,
183 result = [if regex::Regex::new($first_pattern).unwrap().is_match($str) {
184 $first_expr
185 } else if regex::Regex::new($pattern).unwrap().is_match($str) {
186 let closure = |$caps: regex::Captures| $expr;
187 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
188 }],
189 }
190 };
191
192 (
193 tokens = [captures($pattern:expr) => |$caps:ident| $expr:block $($rest:tt)*],
194 str = $str:expr,
195 first_pattern = $first_pattern:expr,
196 first_expr = $first_expr:expr,
197 result = unknown,
198 ) => {
199 $crate::__regexm! {
200 tokens = [$($rest)*],
201 str = $str,
202 first_pattern = $first_pattern,
203 first_expr = $first_expr,
204 result = [if regex::Regex::new($first_pattern).unwrap().is_match($str) {
205 $first_expr
206 } else if regex::Regex::new($pattern).unwrap().is_match($str) {
207 let closure = |$caps: regex::Captures| $expr;
208 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
209 }],
210 }
211 };
212
213 (
214 tokens = [$pattern:expr => $expr:expr, $($rest:tt)*],
215 str = $str:expr,
216 first_pattern = $first_pattern:expr,
217 first_expr = $first_expr:expr,
218 result = unknown,
219 ) => {
220 $crate::__regexm! {
221 tokens = [$($rest)*],
222 str = $str,
223 first_pattern = $first_pattern,
224 first_expr = $first_expr,
225 result = [if regex::Regex::new($first_pattern).unwrap().is_match($str) {
226 $first_expr
227 } else if regex::Regex::new($pattern).unwrap().is_match($str) {
228 $expr
229 }],
230 }
231 };
232
233 (
234 tokens = [$pattern:expr => $expr:block $($rest:tt)*],
235 str = $str:expr,
236 first_pattern = $first_pattern:expr,
237 first_expr = $first_expr:expr,
238 result = unknown,
239 ) => {
240 $crate::__regexm! {
241 tokens = [$($rest)*],
242 str = $str,
243 first_pattern = $first_pattern,
244 first_expr = $first_expr,
245 result = [if regex::Regex::new($first_pattern).unwrap().is_match($str) {
246 $first_expr
247 } else if regex::Regex::new($pattern).unwrap().is_match($str) {
248 $expr
249 }],
250 }
251 };
252
253 (
254 tokens = [captures($pattern:expr) => |$caps:ident| $expr:expr, $($rest:tt)*],
255 str = $str:expr,
256 first_pattern = $first_pattern:expr,
257 first_expr = $first_expr:expr,
258 result = [$($result:tt)*],
259 ) => {
260 $crate::__regexm! {
261 tokens = [$($rest)*],
262 str = $str,
263 first_pattern = $first_pattern,
264 first_expr = $first_expr,
265 result = [$($result)* else if regex::Regex::new($pattern).unwrap().is_match($str) {
266 let closure = |$caps: regex::Captures| $expr;
267 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
268 }],
269 }
270 };
271
272 (
273 tokens = [captures($pattern:expr) => |$caps:ident| $expr:block $($rest:tt)*],
274 str = $str:expr,
275 first_pattern = $first_pattern:expr,
276 first_expr = $first_expr:expr,
277 result = [$($result:tt)*],
278 ) => {
279 $crate::__regexm! {
280 tokens = [$($rest)*],
281 str = $str,
282 first_pattern = $first_pattern,
283 first_expr = $first_expr,
284 result = [$($result)* else if regex::Regex::new($pattern).unwrap().is_match($str) {
285 let closure = |$caps: regex::Captures| $expr;
286 closure(regex::Regex::new($pattern).unwrap().captures($str).unwrap())
287 }],
288 }
289 };
290
291 (
292 tokens = [$pattern:expr => $expr:expr, $($rest:tt)*],
293 str = $str:expr,
294 first_pattern = $first_pattern:expr,
295 first_expr = $first_expr:expr,
296 result = [$($result:tt)*],
297 ) => {
298 $crate::__regexm! {
299 tokens = [$($rest)*],
300 str = $str,
301 first_pattern = $first_pattern,
302 first_expr = $first_expr,
303 result = [$($result)* else if regex::Regex::new($pattern).unwrap().is_match($str) {
304 $expr
305 }],
306 }
307 };
308
309 (
310 tokens = [$pattern:expr => $expr:block $($rest:tt)*],
311 str = $str:expr,
312 first_pattern = $first_pattern:expr,
313 first_expr = $first_expr:expr,
314 result = [$($result:tt)*],
315 ) => {
316 $crate::__regexm! {
317 tokens = [$($rest)*],
318 str = $str,
319 first_pattern = $first_pattern,
320 first_expr = $first_expr,
321 result = [$($result)* else if regex::Regex::new($pattern).unwrap().is_match($str) {
322 $expr
323 }],
324 }
325 };
326}
327
328#[cfg(test)]
329mod test {
330 #[test]
331 fn test_match_3_or_more_pattern() {
332 regexm!(match "2021-01-01" {
333 r"^\d{4}-\d{2}-\d{2}$" => assert!(true),
334 r"^\d{4}-\d{2}$" => assert!(false),
335 _ => assert!(false),
336 });
337
338 regexm!(match "foo" {
339 r"^\d{4}-\d{2}-\d{2}$" => assert!(false),
340 r"^\d{4}-\d{2}$" => assert!(false),
341 _ => assert!(true),
342 });
343
344 regexm!(match "2021-01-01" {
345 r"^\d{4}-\d{2}-\d{2}$" => assert!(true),
346 r"^\d{4}-\d{2}$" => assert!(false),
347 r"^\d{4}$" => assert!(false),
348 _ => assert!(false),
349 });
350 }
351
352 #[test]
353 fn test_match_3_or_more_pattern_block() {
354 regexm!(match "2021-01-01" {
355 r"^\d{4}-\d{2}-\d{2}$" => {
356 assert!(true);
357 assert!(true);
358 }
359 r"^\d{4}-\d{2}$" => {
360 assert!(false);
361 assert!(false);
362 }
363 _ => {
364 assert!(false);
365 assert!(false)
366 }
367 });
368
369 regexm!(match "foo" {
370 r"^\d{4}-\d{2}-\d{2}$" => {
371 assert!(false);
372 assert!(false);
373 }
374 r"^\d{4}-\d{2}$" => {
375 assert!(false);
376 assert!(false);
377 }
378 _ => {
379 assert!(true);
380 assert!(true)
381 }
382 });
383
384 regexm!(match "2021-01-01" {
385 r"^\d{4}-\d{2}-\d{2}$" => {
386 assert!(true);
387 assert!(true);
388 }
389 r"^\d{4}-\d{2}$" => {
390 assert!(false);
391 assert!(false);
392 }
393 r"^\d{4}$" => {
394 assert!(false);
395 assert!(false);
396 }
397 _ => {
398 assert!(false);
399 assert!(false)
400 }
401 });
402 }
403
404 #[test]
405 fn test_match_2_or_less_pattern() {
406 regexm!(match "2021-01-01" {
407 r"^\d{4}-\d{2}-\d{2}$" => assert!(true),
408 _ => assert!(false),
409 });
410
411 regexm!(match "foo" {
412 r"^\d{4}-\d{2}$" => assert!(false),
413 _ => assert!(true),
414 });
415 }
416
417 #[test]
418 fn test_match_2_or_less_pattern_block() {
419 regexm!(match "2021-01-01" {
420 r"^\d{4}-\d{2}-\d{2}$" => {
421 assert!(true);
422 assert!(true);
423 }
424 _ => {
425 assert!(false);
426 assert!(false)
427 }
428 });
429
430 regexm!(match "foo" {
431 r"^\d{4}-\d{2}$" => {
432 assert!(false);
433 assert!(false)
434 }
435 _ => {
436 assert!(true);
437 assert!(true);
438 }
439 });
440 }
441
442 #[test]
443 fn test_let_match_3_or_more_pattern() {
444 let foo = regexm!(match "2021-01-01" {
445 r"^\d{4}-\d{2}-\d{2}$" => "yyyy-mm-dd",
446 r"^\d{4}-\d{2}$" => "yyyy-mm",
447 _ => "default",
448 });
449 assert_eq!(foo, "yyyy-mm-dd");
450
451 let foo = regexm!(match "foo" {
452 r"^\d{4}-\d{2}-\d{2}$" => "yyyy-mm-dd",
453 r"^\d{4}-\d{2}$" => "yyyy-mm",
454 _ => "default",
455 });
456 assert_eq!(foo, "default");
457
458 let foo = regexm!(match "2021-01-01" {
459 r"^\d{4}-\d{2}-\d{2}$" => "yyyy-mm-dd",
460 r"^\d{4}-\d{2}$" => "yyyy-mm",
461 r"^\d{4}$" => "yyyy",
462 _ => "default",
463 });
464 assert_eq!(foo, "yyyy-mm-dd");
465 }
466
467 #[test]
468 fn test_let_match_3_or_more_pattern_block() {
469 let foo = regexm!(match "2021-01-01" {
470 r"^\d{4}-\d{2}-\d{2}$" => {
471 let bar = "yyyy-mm-dd";
472 bar
473 }
474 r"^\d{4}-\d{2}$" => {
475 let bar = "yyyy-mm";
476 bar
477 }
478 _ => "default",
479 });
480 assert_eq!(foo, "yyyy-mm-dd");
481
482 let foo = regexm!(match "foo" {
483 r"^\d{4}-\d{2}-\d{2}$" => {
484 let bar = "yyyy-mm-dd";
485 bar
486 }
487 r"^\d{4}-\d{2}$" => {
488 let bar = "yyyy-mm";
489 bar
490 }
491 _ => "default",
492 });
493 assert_eq!(foo, "default");
494
495 let foo = regexm!(match "2021-01-01" {
496 r"^\d{4}-\d{2}-\d{2}$" => {
497 let bar = "yyyy-mm-dd";
498 bar
499 }
500 r"^\d{4}-\d{2}$" => {
501 let bar = "yyyy-mm";
502 bar
503 }
504 r"^\d{4}$" => {
505 let bar = "yyyy";
506 bar
507 }
508 _ => "default",
509 });
510 assert_eq!(foo, "yyyy-mm-dd");
511 }
512
513 #[test]
514 fn test_let_match_2_or_less_pattern() {
515 let foo = regexm!(match "2021-01-01" {
516 r"^\d{4}-\d{2}-\d{2}$" => "yyyy-mm-dd",
517 _ => "default",
518 });
519 assert_eq!(foo, "yyyy-mm-dd");
520
521 let foo = regexm!(match "foo" {
522 r"^\d{4}-\d{2}$" => "yyyy-mm",
523 _ => "default",
524 });
525 assert_eq!(foo, "default");
526 }
527
528 #[test]
529 fn test_let_match_2_or_less_pattern_block() {
530 let foo = regexm!(match "2021-01-01" {
531 r"^\d{4}-\d{2}-\d{2}$" => {
532 let bar = "yyyy-mm-dd";
533 bar
534 }
535 _ => "default",
536 });
537 assert_eq!(foo, "yyyy-mm-dd");
538
539 let foo = regexm!(match "foo" {
540 r"^\d{4}-\d{2}$" => {
541 let bar = "yyyy-mm";
542 bar
543 }
544 _ => "default",
545 });
546 assert_eq!(foo, "default");
547 }
548
549 #[test]
550 fn test_capture_groups_match_3_or_more_pattern() {
551 regexm!(match "2021-01-01" {
552 captures(r"^(\d{4})-\d{2}-\d{2}$") =>
553 |caps| assert_eq!(caps.get(1).map_or("", |m| m.as_str()), "2021"),
554 r"^\d{4}-\d{2}$" => assert!(false),
555 _ => assert!(false),
556 });
557
558 regexm!(match "2021-01" {
559 r"^\d{4}-\d{2}-\d{2}$" => assert!(false),
560 captures(r"^(\d{4})-\d{2}$") =>
561 |caps| assert_eq!(caps.get(1).map_or("", |m| m.as_str()), "2021"),
562 r"^\d{4}$" => assert!(false),
563 _ => assert!(false),
564 });
565 }
566
567 #[test]
568 fn test_capture_groups_match_3_or_more_pattern_block() {
569 regexm!(match "2021-01-01" {
570 captures(r"^(\d{4})-\d{2}-\d{2}$") => |caps| {
571 let year = caps.get(1).map_or("", |m| m.as_str());
572 assert_eq!(year, "2021")
573 }
574 r"^\d{4}-\d{2}$" => {
575 assert!(false);
576 assert!(false);
577 }
578 _ => {
579 assert!(false);
580 assert!(false)
581 }
582 });
583
584 regexm!(match "2021-01" {
585 r"^\d{4}-\d{2}-\d{2}$" => {
586 assert!(false);
587 assert!(false);
588 }
589 captures(r"^(\d{4})-\d{2}$") => |caps| {
590 let month = caps.get(1).map_or("", |m| m.as_str());
591 assert_eq!(month, "2021")
592 }
593 r"^\d{4}$" => {
594 assert!(false);
595 assert!(false);
596 }
597 _ => {
598 assert!(false);
599 assert!(false)
600 }
601 });
602 }
603
604 #[test]
605 fn test_capture_groups_match_2_or_less_pattern() {
606 regexm!(match "2021-01-01" {
607 captures(r"^(\d{4})-\d{2}-\d{2}$") =>
608 |caps| assert_eq!(caps.get(1).map_or("", |m| m.as_str()), "2021"),
609 _ => assert!(false),
610 });
611
612 regexm!(match "foo" {
613 r"^\d{4}-\d{2}$" => assert!(false),
614 _ => assert!(true),
615 });
616 }
617
618 #[test]
619 fn test_capture_groups_match_2_or_less_pattern_block() {
620 regexm!(match "2021-01-01" {
621 captures(r"^(\d{4})-\d{2}-\d{2}$") => |caps| {
622 let year = caps.get(1).map_or("", |m| m.as_str());
623 assert_eq!(year, "2021");
624 }
625 _ => {
626 assert!(false);
627 assert!(false)
628 }
629 });
630 }
631}