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}