try_guard/lib.rs
1//! The [`guard!`] macro.
2//!
3//! The [`guard!`] macro implements a control-flow sugar that occurs very often in common Rust code:
4//!
5//! ```rust
6//! fn foo(cond: bool) -> Option<i32> {
7//! if !cond {
8//! return None;
9//! }
10//!
11//! // do something useful
12//!
13//! Some(42)
14//! }
15//! ```
16//!
17//! This pattern of testing arguments and early-returning with an error is very typical.
18//! Unfortunately, the [`?`] operator doesn’t help us here because we want to early-return on a
19//! boolean value, not an error value.
20//!
21//! A not very idiomatic and weird way to rewrite that:
22//!
23//! ```rust
24//! fn foo(cond: bool) -> Option<i32> {
25//! if cond { Some(()) } else { None }?;
26//! Some(42)
27//! }
28//! ```
29//!
30//! This crate provides the [`guard!`] macro — analoguous to the [`guard`] Haskell `Alternative`
31//! function — that helps early-return from a function if a predicate is `false`:
32//!
33//! ```rust
34//! # #![cfg_attr(feature = "test-nightly", feature(try_trait))]
35//! # #[cfg(feature = "test-nightly")] mod lol {
36//! use try_guard::guard;
37//!
38//! fn foo(cond: bool) -> Option<i32> {
39//! guard!(cond);
40//! Some(42)
41//! }
42//! # }
43//! ```
44//!
45//! ## Custom guard types
46//!
47//! This crate also allows you to _guard_ to anything that implements [`Try<Error = NoneError>`] or
48//! `From<NoneError>` (nightly only).
49//!
50//! For instance, the following works:
51//!
52//! ```rust
53//! # #![cfg_attr(feature = "test-nightly", feature(try_trait))]
54//! # #[cfg(feature = "test-nightly")] mod lol {
55//! use std::ops::Try;
56//! use std::option::NoneError;
57//! use try_guard::guard;
58//!
59//! #[derive(Clone, Debug, Eq, PartialEq)]
60//! enum MyGuard<T> {
61//! Just(T),
62//! Nothing
63//! }
64//!
65//! impl<T> MyGuard<T> {
66//! fn new(x: T) -> Self {
67//! MyGuard::Just(x)
68//! }
69//!
70//! fn none() -> Self {
71//! MyGuard::Nothing
72//! }
73//! }
74//!
75//! impl<T> Try for MyGuard<T> {
76//! type Ok = T;
77//!
78//! type Error = NoneError;
79//!
80//! fn from_error(_: Self::Error) -> Self {
81//! MyGuard::none()
82//! }
83//!
84//! fn from_ok(x: Self::Ok) -> Self {
85//! MyGuard::new(x)
86//! }
87//!
88//! fn into_result(self) -> Result<Self::Ok, Self::Error> {
89//! match self {
90//! MyGuard::Just(x) => Ok(x),
91//! MyGuard::Nothing => Err(NoneError)
92//! }
93//! }
94//! }
95//!
96//! fn foo(cond: bool) -> MyGuard<i32> {
97//! guard!(cond);
98//! MyGuard::new(42)
99//! }
100//!
101//! fn main() {
102//! assert_eq!(foo(false), MyGuard::Nothing);
103//! }
104//! # }
105//! ```
106//!
107//! ## More control on the error type
108//!
109//! If you’d rather manipulate the error type when the predicate is false, you might be interested
110//! in the [`verify!`] macro instead. That macro is akin to [`guard!`] but instead doesn’t exit the
111//! current scope: it maps the predicate’s truth to either `Some(())` or `None`, allowing you to
112//! call `Option::ok_or` or whatever error combinator you want to.
113//!
114//! ```rust
115//! use try_guard::verify;
116//!
117//! fn foo(cond: bool) -> Result<u32, String> {
118//! verify!(cond).ok_or("bad condition".to_owned())?;
119//! Ok(123)
120//! }
121//! ```
122//!
123//! ## Feature flags
124//!
125//! - The `test-nightly` feature flag can be used to test nightly-related features that come
126//! freely and don’t require a nightly build of rustc to compile this crate but require one at
127//! use site.
128//!
129//! [`guard!`]: guard
130//! [`verify!`]: verify
131//! [`guard`]: http://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#v:guard
132//! [`?`]: https://doc.rust-lang.org/std/ops/trait.Try.html
133//! [`Try<Error = NoneError>`]: https://doc.rust-lang.org/std/ops/trait.Try.html
134
135/// The [`guard!`] macro.
136///
137/// [`guard!`]: guard
138#[macro_export]
139macro_rules! guard {
140 ($e:expr) => {
141 if !$e {
142 None?
143 }
144 };
145}
146
147/// A version of [`guard!`] that doesn’t shortcut.
148///
149/// The advantage of this macro over [`guard!`] is to allow you to manipulate the resulting
150/// [`Option`].
151///
152/// [`guard!`]: guard
153#[macro_export]
154macro_rules! verify {
155 ($e:expr) => {
156 if !$e {
157 None
158 } else {
159 Some(())
160 }
161 }
162}