Last active
October 9, 2023 19:17
-
-
Save JustusAdam/6225eaf4271a5e194a7efcd56da7a520 to your computer and use it in GitHub Desktop.
Monad-like quantifiers for Rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Monadic quantifiers for Rust iterators. | |
/// | |
/// Allows you to pseudo-monadically create a `bool` computation with iterators. | |
/// It exposes the iterator methods `any` and `all` as prefix bindings and also | |
/// enables pattern matching and guarding. | |
/// | |
/// The macro expands a sequence of statements. All usual Rust statements are | |
/// supported and only the top-level statements are expanded with the special | |
/// syntax, not e.g. nested blocks. | |
/// | |
/// It supports the following syntax: | |
/// | |
/// ```ignored | |
/// any pattern <- source; | |
/// all pattern <- source; | |
/// guard expression; | |
/// ``` | |
/// | |
/// `any` and `all` correspond to the usual iterator methods, but the difference | |
/// is that they do not require nesting. Instead the statements following them | |
/// are interpreted as their body. In addition the `pattern` failure is handled | |
/// implicitly. In the case of `all`, if the pattern doesn't match it simply | |
/// returns `true`, e.g. it only enforces the subsequent conditions for matched | |
/// patterns. In the case of `any` a failing pattern match returns `false`, e.g. | |
/// the search for a matching element continues. | |
/// | |
/// `guard condition` enforces `condition`. If the condition does not hold | |
/// `false` is returned. You may also use it as `guard pattern = expr` in which | |
/// case `false` is returned if the pattern does not match. | |
macro_rules! iterator_quantifiers { | |
(guard $e:expr; $($rest:tt)*) => { | |
if !$e { | |
return false; | |
} | |
iterator_quantifiers!($($rest)*); | |
}; | |
(guard $pat:pat = $e:expr; $($rest:tt)*) => { | |
let $pat = !$e { | |
return false | |
}; | |
iterator_quantifiers!($($rest)*); | |
}; | |
(any $pat:pat_param = $e:expr; $($rest:tt)*) => { | |
return $e.into_iter().any(|ident| if let $pat = ident { | |
iterator_quantifiers!($($rest)*); | |
} else { | |
false | |
}); | |
}; | |
(all $pat:pat_param = $e: expr; $($rest:tt)*) => { | |
return $e.into_iter().all(|ident| if let $pat = ident { | |
iterator_quantifiers!($($rest)*); | |
} else { true }) | |
}; | |
($s:stmt; $($rest:tt)*) => { | |
$s; | |
iterator_quantifiers!($($rest)*) | |
}; | |
($e:expr) => { | |
return $e | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment