check/
lib.rs

1//! Convenience `assert!`-like macros which immediately returns `None` or `Err(...)` instead of
2//! panicking.
3//!
4//! # Examples
5//!
6//! In a function returning an `Option<T>`, invoke the macro with just enough parameters to get a
7//! condition to check.
8//!
9//! ```
10//! # use check::{check_eq, check};
11//! # fn a() -> Option<()> {
12//! # let (a, b, n) = (1, 1, 10);
13//! check!(a < n);
14//! check_eq!(a, b);
15//! # Some(())
16//! # }
17//! ```
18//!
19//! This will expand to:
20//!
21//! ```
22//! # fn a() -> Option<()> {
23//! # let (a, b, n) = (1, 1, 10);
24//! if !(a < n) {
25//!   return None;
26//! }
27//! if a != b {
28//!   return None;
29//! }
30//! # Some(())
31//! # }
32//! ```
33//!
34//! In a function returning a `Result<T, E>`, invoke the macro with an extra argument, which is the
35//! error to return if the check fails (and must have type `E`), just like you can add arguments to
36//! choose a panic message with `assert!`.
37//!
38//! ```
39//! # use check::{check_eq, check};
40//! # enum MyError { TooBig, NotEqual }
41//! # fn a() -> Result<(), MyError> {
42//! # let (a, b, n) = (1, 1, 10);
43//! check!(a < n, MyError::TooBig);
44//! check_eq!(a, b, MyError::NotEqual);
45//! # Ok(())
46//! # }
47//! ```
48//!
49//! This will expand to:
50//!
51//! ```
52//! # enum MyError { TooBig, NotEqual }
53//! # fn a() -> Result<(), MyError> {
54//! # let (a, b, n) = (1, 1, 10);
55//! if !(a < n) {
56//!   return Err(MyError::TooBig);
57//! }
58//! if a != b {
59//!   return Err(MyError::NotEqual);
60//! }
61//! # Ok(())
62//! # }
63//! ```
64//!
65//! # Note
66//!
67//! Actually, the two following lines are quite equivalent:
68//!
69//! ```
70//! # use check::check;
71//! # fn a() -> Option<()> {
72//! # let (a, b) = (1, 1);
73//! check!(a <= b);
74//! (a <= b).then(|| ())?;
75//! # Some(())
76//! # }
77//! ```
78//!
79
80#![no_std]
81#![warn(missing_docs)]
82
83/// Exits the function prematurely if the condition is not met.
84///
85/// # Examples
86///
87/// ```
88/// use check::check;
89///
90/// fn foo(a: i32, n: i32) -> Option<()> {
91///     check!(a < n);
92///     // If the code reaches this line, then you know that `a < n`.
93///     // If it was not true, `None` was returned.
94///     Some(())
95/// }
96/// ```
97///
98/// ```
99/// use check::check;
100///
101/// enum MyError {
102///     TooBig,
103///     NotEqual,
104/// }
105///
106/// fn foo(a: i32, n: i32) -> Result<(), MyError> {
107///     check!(a < n, MyError::TooBig);
108///     // If the code reaches this line, then you know that `a < n`.
109///     // If it was not true, `Err(MyError::TooBig)` was returned.
110///     Ok(())
111/// }
112/// ```
113#[macro_export]
114macro_rules! check {
115    ($cond:expr $(,)?) => {
116        if !($cond) {
117            return None;
118        }
119    };
120    ($cond:expr, $e: expr $(,)?) => {
121        if !($cond) {
122            return Err($e);
123        }
124    };
125}
126
127/// Exits the function prematurely if the two expressions do not evaluate the same.
128///
129/// # Examples
130///
131/// ```
132/// use check::check_eq;
133///
134/// fn foo(a: i32, b: i32) -> Option<()> {
135///     check_eq!(a, b);
136///     // If the code reaches this line, then you know that `a == b`.
137///     // If it was not true, `None` was returned.
138///     Some(())
139/// }
140/// ```
141///
142/// ```
143/// use check::check_eq;
144///
145/// enum MyError {
146///     TooBig,
147///     NotEqual,
148/// }
149///
150/// fn foo(a: i32, b: i32) -> Result<(), MyError> {
151///     check_eq!(a, b, MyError::NotEqual);
152///     // If the code reaches this line, then you know that `a == b`.
153///     // If it was not true, `Err(MyError::NotEqual)` was returned.
154///     Ok(())
155/// }
156/// ```
157#[macro_export]
158macro_rules! check_eq {
159    ($a:expr, $b:expr $(,)?) => {
160        if $a != $b {
161            return None;
162        }
163    };
164    ($a:expr, $b:expr, $e: expr $(,)?) => {
165        if $a != $b {
166            return Err($e);
167        }
168    };
169}
170
171/// Exits the function prematurely if the two expressions evaluate the same.
172///
173/// # Examples
174///
175/// ```
176/// use check::check_ne;
177///
178/// fn foo(a: i32, b: i32) -> Option<()> {
179///     check_ne!(a, b);
180///     // If the code reaches this line, then you know that `a != b`.
181///     // If it was not true, `None` was returned.
182///     Some(())
183/// }
184/// ```
185///
186/// ```
187/// use check::check_ne;
188///
189/// enum MyError {
190///     TooBig,
191///     Equal,
192/// }
193///
194/// fn foo(a: i32, b: i32) -> Result<(), MyError> {
195///     check_ne!(a, b, MyError::Equal);
196///     // If the code reaches this line, then you know that `a != b`.
197///     // If it was not true, `Err(MyError::Equal)` was returned.
198///     Ok(())
199/// }
200/// ```
201#[macro_export]
202macro_rules! check_ne {
203    ($a:expr, $b:expr $(,)?) => {
204        if $a == $b {
205            return None;
206        }
207    };
208    ($a:expr, $b:expr, $e: expr $(,)?) => {
209        if $a == $b {
210            return Err($e);
211        }
212    };
213}
214
215#[cfg(test)]
216mod tests {
217    #[test]
218    fn check_works() {
219        fn o(a: i32) -> Option<i32> {
220            check!(a < 10);
221            Some(a + 1)
222        }
223        fn r(a: i32) -> Result<i32, i32> {
224            check!(a < 10, a);
225            Ok(a + 1)
226        }
227
228        assert_eq!(o(9), Some(10));
229        assert_eq!(o(10), None);
230        assert_eq!(r(9), Ok(10));
231        assert_eq!(r(10), Err(10));
232    }
233
234    #[test]
235    fn check_eq_works() {
236        fn o(a: i32) -> Option<i32> {
237            check_eq!(a, 9);
238            Some(a + 1)
239        }
240        fn r(a: i32) -> Result<i32, i32> {
241            check_eq!(a, 9, a);
242            Ok(a + 1)
243        }
244
245        assert_eq!(o(9), Some(10));
246        assert_eq!(o(10), None);
247        assert_eq!(r(9), Ok(10));
248        assert_eq!(r(10), Err(10));
249    }
250
251    #[test]
252    fn check_ne_works() {
253        fn o(a: i32) -> Option<i32> {
254            check_ne!(a, 9);
255            Some(a + 1)
256        }
257        fn r(a: i32) -> Result<i32, i32> {
258            check_ne!(a, 9, a);
259            Ok(a + 1)
260        }
261
262        assert_eq!(o(9), None);
263        assert_eq!(o(10), Some(11));
264        assert_eq!(r(9), Err(9));
265        assert_eq!(r(10), Ok(11));
266    }
267}