soft_assert/
lib.rs

1#![deny(missing_docs)]
2#![no_std]
3
4//! A set of macros similar to the standard library's `assert_*` macros, but return early instead of panicking.
5//! # Example
6//! ```
7//! use soft_assert::*;
8//!
9//! fn not_twenty(x: i32) -> Option<i32> {
10//!     // This will return `Option::default()`, which is `None`
11//!     soft_assert_ne!(x, 20);
12//!     Some(x)
13//! }
14//!
15//! fn double_if_greater_than_5(x: i32) -> i32 {
16//!     // But here we don't want to return `i32::default()`,
17//!     // so we specify a return value.
18//!     soft_assert!(x > 5, x);
19//!     x * 2
20//! }
21//!
22//! fn main() {
23//!     assert!(not_twenty(10).is_some());   
24//!     assert!(not_twenty(20).is_none());   
25//!
26//!     let doubled = double_if_greater_than_5(13);
27//!     assert_eq!(doubled, 26);    
28//!     let not_doubled = double_if_greater_than_5(2);
29//!     assert_eq!(not_doubled, 2);   
30//! }
31//!
32//! ```
33//!
34//! This crate is `#![no_std]`
35
36#[macro_export]
37/// Asserts a condition is true, returning otherwise.
38///
39/// Non-panicking version of [`assert`](https://doc.rust-lang.org/std/macro.assert.html).
40///
41/// # Custom return values
42/// Unless otherwise specified, this will return the default value of the return type (if it has one).
43/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
44/// i.e. `soft_assert!(false, Err(e))`. Ownership of any captured values is only taken if the assertion fails, so you can
45/// continue to use them later on.
46///
47/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
48macro_rules! soft_assert {
49    ($e:expr) => {
50        if !$e {
51            return Default::default();
52        }
53    };
54    ($e:expr,) => {
55        $crate::soft_assert!($e)
56    };
57    ($e:expr, $failed:expr) => {
58        if !$e {
59            return $failed;
60        }
61    };
62    ($e:expr, $failed:expr,) => {
63        $crate::soft_assert!($e)
64    };
65}
66
67/// Asserts two values are equal, returning otherwise.
68///
69/// Non-panicking version of [`assert_eq`](https://doc.rust-lang.org/std/macro.assert_eq.html).
70///
71/// # Custom return values
72/// Unless otherwise specified, this will return the default value of the return type (if it has one).
73/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
74/// i.e. `soft_assert_eq!(1, 2, Err(e))`. Ownership of any captured values is only taken if the assertion fails, so you can
75/// continue to use them later on.
76///
77/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
78#[macro_export]
79macro_rules! soft_assert_eq {
80    ($x:expr, $y:expr) => {
81        if { $x } != { $y } {
82            return Default::default();
83        }
84    };
85    ($x:expr, $y:expr,) => {
86        $crate::soft_assert_eq!($x, $y)
87    };
88    ($x:expr, $y:expr, $failed:expr) => {
89        if { $x } != { $y } {
90            return $failed;
91        }
92    };
93    ($x:expr, $y:expr, $failed:expr,) => {
94        $crate::soft_assert_eq!($x, $y, $failed)
95    };
96}
97
98/// Asserts two values are not equal, returning otherwise.
99///
100/// Non-panicking version of [`assert_ne`](https://doc.rust-lang.org/std/macro.assert_ne.html).
101///
102/// # Custom return values
103/// Unless otherwise specified, this will return the default value of the return type (if it has one).
104/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
105/// i.e. `soft_assert_ne!(2 + 2, 4, Err(e))`. Ownership of any captured values is only taken if the assertion fails, so you can
106/// continue to use them later on.
107///
108/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
109#[macro_export]
110macro_rules! soft_assert_ne {
111    ($x:expr, $y:expr) => {
112        if { $x } == { $y } {
113            return Default::default();
114        }
115    };
116    ($x:expr, $y:expr,) => {
117        $crate::soft_assert_ne!($x, $y)
118    };
119    ($x:expr, $y:expr, $failed:expr) => {
120        if { $x } == { $y } {
121            return $failed;
122        }
123    };
124    ($x:expr, $y:expr, $failed:expr,) => {
125        $crate::soft_assert_ne!($x, $y, $failed)
126    };
127}
128
129#[macro_export]
130/// Asserts a value matches a pattern, returning otherwise.
131///
132/// Non-panicking version of [`assert_matches`](https://doc.rust-lang.org/std/assert_matches/macro.assert_matches.html).
133///
134/// # Custom return values
135/// Unless otherwise specified, this will return the default value of the return type (if it has one).
136/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
137/// i.e. `soft_assert_matches!(x, None, Err(e))`. Ownership of any captured values is only taken if the assertion fails, so you can
138/// continue to use them later on.
139///
140/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
141macro_rules! soft_assert_matches {
142    ($e:expr, $p:pat) => {
143        match $e {
144            $p => (),
145            _ => return Default::default();
146        }
147    };
148    ($e:expr, $p:pat,) => {
149        $crate::soft_assert_matches!($x, $y)
150    };
151    ($e:expr, $p:pat, $failed:expr) => {
152        match $e {
153            $p => (),
154            _ => return $failed;
155        }
156    };
157    ($e:expr, $p:pat, $failed:expr,) => {
158        $crate::soft_assert_matches!($x, $y, $failed)
159    };
160}
161
162/// If debug assertions are enabled, asserts a condition is true, returning otherwise.
163///
164/// Non-panicking version of [`debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
165///
166/// # Custom return values
167/// Unless otherwise specified, this will return the default value of the return type (if it has one).
168/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
169/// i.e. `soft_debug_assert!(false, Err(e))`. Ownership of the value is only taken if the assertion fails, so you can
170/// continue to use them later on.
171///
172/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
173#[macro_export]
174macro_rules! soft_debug_assert {
175    ($e:expr) => {
176        #[cfg(debug_assertions)]
177        $crate::soft_assert!($e);
178    };
179    ($e:expr,) => {
180        $crate::soft_debug_assert!($e);
181    };
182    ($e:expr, $failed:expr) => {
183        #[cfg(debug_assertions)]
184        $crate::soft_assert!($e, $failed);
185    };
186    ($e:expr, $failed:expr,) => {
187        #[cfg(debug_assertions)]
188        $crate::soft_assert!($e, $failed);
189    };
190}
191
192/// If debug assertions are enabled, asserts two values are equal, returning otherwise.
193///
194/// Non-panicking version of [`debug_assert_eq`](https://doc.rust-lang.org/std/macro.debug_assert_eq.html).
195///
196/// # Custom return values
197/// Unless otherwise specified, this will return the default value of the return type (if it has one).
198/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
199/// i.e. `soft_debug_assert_eq!(1, 2, Err(e))`. Ownership of the value is only taken if the assertion fails, so you can
200/// continue to use them later on.
201///
202/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
203#[macro_export]
204macro_rules! soft_debug_assert_eq {
205    ($x:expr, $y:expr) => {
206        #[cfg(debug_assertions)]
207        $crate::soft_assert_eq!($x, $y);
208    };
209    ($x:expr, $y:expr,) => {
210        $crate::soft_debug_assert_eq!($x, $y);
211    };
212    ($x:expr, $y:expr, $failed:expr) => {
213        #[cfg(debug_assertions)]
214        $crate::soft_assert_eq!($x, $y, $failed);
215    };
216    ($x:expr, $y:expr, $failed:expr,) => {
217        $crate::soft_debug_assert_eq!($x, $y, $failed);
218    };
219}
220
221/// If debug assertions are enabled, asserts two values are not equal, returning otherwise.
222///
223/// Non-panicking version of [`debug_assert_ne`](https://doc.rust-lang.org/std/macro.debug_assert.html).
224///
225/// # Custom return values
226/// Unless otherwise specified, this will return the default value of the return type (if it has one).
227/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
228/// i.e. `soft_debug_assert_ne!(2 + 2, 4, Err(e))`. Ownership of the value is only taken if the assertion fails, so you can
229/// continue to use them later on.
230///
231/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
232#[macro_export]
233macro_rules! soft_debug_assert_ne {
234    ($x:expr, $y:expr) => {
235        #[cfg(debug_assertions)]
236        $crate::soft_assert_ne!($x, $y);
237    };
238    ($x:expr, $y:expr,) => {
239        $crate::soft_debug_assert_ne!($x, $y);
240    };
241    ($x:expr, $y:expr, $failed:expr) => {
242        #[cfg(debug_assertions)]
243        $crate::soft_assert_ne!($x, $y, $failed);
244    };
245    ($x:expr, $y:expr, $failed:expr,) => {
246        $crate::soft_debug_assert_ne!($x, $y, $failed);
247    };
248}
249
250#[macro_export]
251/// Asserts a value matches a pattern, returning otherwise.
252///
253/// Non-panicking version of [`debug_assert_matches`](https://doc.rust-lang.org/std/assert_matches/macro.debug_assert_matches.html).
254///
255/// # Custom return values
256/// Unless otherwise specified, this will return the default value of the return type (if it has one).
257/// A custom value can be returned instead by supplying it as an additional argument (similar to `assert`'s custom message),
258/// i.e. `soft_debug_assert_match!(x, None, Err(e))`. Ownership of any captured values is only taken if the assertion fails, so you can
259/// continue to use them later on.
260///
261/// This does *not* perform `Err(..)`-wrapping, to allow returning any value.
262macro_rules! soft_debug_assert_matches {
263    ($e:expr, $p:pat) => {
264        #[cfg(debug_assertions)]
265        $crate::soft_assert_match!($e, $p);
266    };
267    ($e:expr, $p:pat,) => {
268        $crate::soft_debug_assert_match!($e, $p);
269    };
270    ($e:expr, $p:pat, $failed:expr) => {
271        #[cfg(debug_assertions)]
272        $crate::soft_assert_match!($e, $p, $failed);
273    };
274    ($e:expr, $p:pat, $failed:expr,) => {
275        $crate::soft_debug_assert_match!($e, $p, $failed);
276    };
277}
278
279#[cfg(test)]
280mod tests {
281    use super::*;
282
283    #[test]
284    fn test() {
285        assert!((|| {
286            soft_assert!(true, false);
287            true
288        })());
289        assert!((|| {
290            soft_assert!(false, true);
291            false
292        })());
293        assert!((|| {
294            soft_assert_eq!((1..=10).sum::<i32>(), 55, false);
295            true
296        })());
297        assert!((|| {
298            soft_assert_eq!((1..=10).sum::<i32>(), 3141, true);
299            false
300        })());
301        assert!((|| {
302            soft_assert_ne!((1..=10).sum::<i32>(), 3151, false);
303            true
304        })());
305        assert!((|| {
306            soft_assert_ne!((1..=10).sum::<i32>(), 55, true);
307            false
308        })());
309    }
310}