Skip to content

Instantly share code, notes, and snippets.

@JustusAdam
Last active October 9, 2023 19:17
Show Gist options
  • Save JustusAdam/6225eaf4271a5e194a7efcd56da7a520 to your computer and use it in GitHub Desktop.
Save JustusAdam/6225eaf4271a5e194a7efcd56da7a520 to your computer and use it in GitHub Desktop.
Monad-like quantifiers for Rust
/// 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