Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hadronized/try-guard
A guard! macro inspired by the guard Alternative function from Haskell.
https://github.com/hadronized/try-guard
Last synced: about 1 month ago
JSON representation
A guard! macro inspired by the guard Alternative function from Haskell.
- Host: GitHub
- URL: https://github.com/hadronized/try-guard
- Owner: hadronized
- License: other
- Created: 2019-05-07T14:23:26.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2019-06-07T08:33:24.000Z (over 5 years ago)
- Last Synced: 2024-11-14T22:10:23.176Z (about 1 month ago)
- Language: Rust
- Size: 21.5 KB
- Stars: 6
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# The `guard` Haskell `Alternative` function brought to Rust
The [`guard!`] macro.
The [`guard!`] macro implements a control-flow sugar that occurs very often in common Rust code:
```rust
fn foo(cond: bool) -> Option {
if !cond {
return None;
}// do something useful
Some(42)
}
```This pattern of testing arguments and early-returning with an error is very typical.
Unfortunately, the [`?`] operator doesn’t help us here because we want to early-return on a
boolean value, not an error value.A not very idiomatic and weird way to rewrite that:
```rust
fn foo(cond: bool) -> Option {
if cond { Some(()) } else { None }?;
Some(42)
}
```This crate provides the [`guard!`] macro — analoguous to the [`guard`] Haskell `Alternative`
function — that helps early-return from a function if a predicate is `false`:```rust
use try_guard::guard;fn foo(cond: bool) -> Option {
guard!(cond);
Some(42)
}
```## Custom guard types
This crate also allows you to _guard_ to anything that implements [`Try`] or
`From` (nightly only).For instance, the following works:
```rust
use std::ops::Try;
use std::option::NoneError;
use try_guard::guard;#[derive(Clone, Debug, Eq, PartialEq)]
enum MyGuard {
Just(T),
Nothing
}impl MyGuard {
fn new(x: T) -> Self {
MyGuard::Just(x)
}fn none() -> Self {
MyGuard::Nothing
}
}impl Try for MyGuard {
type Ok = T;type Error = NoneError;
fn from_error(_: Self::Error) -> Self {
MyGuard::none()
}fn from_ok(x: Self::Ok) -> Self {
MyGuard::new(x)
}fn into_result(self) -> Result {
match self {
MyGuard::Just(x) => Ok(x),
MyGuard::Nothing => Err(NoneError)
}
}
}fn foo(cond: bool) -> MyGuard {
guard!(cond);
MyGuard::new(42)
}fn main() {
assert_eq!(foo(false), MyGuard::Nothing);
}
```## More control on the error type
If you’d rather manipulate the error type when the predicate is false, you might be interested
in the [`verify!`] macro instead. That macro is akin to [`guard!`] but instead doesn’t exit the
current scope: it maps the predicate’s truth to either `Some(())` or `None`, allowing you to
call `Option::ok_or` or whatever error combinator you want to.```rust
use try_guard::verify;fn foo(cond: bool) -> Result {
verify!(cond).ok_or("bad condition".to_owned())?;
Ok(123)
}
```## Feature flags
- The `test-nightly` feature flag can be used to test nightly-related features that come
freely and don’t require a nightly build of rustc to compile this crate but require one at
use site.[`guard!`]: guard
[`verify!`]: verify
[`guard`]: http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#v:guard
[`?`]: https://doc.rust-lang.org/std/ops/trait.Try.html
[`Try`]: https://doc.rust-lang.org/std/ops/trait.Try.html