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}