assertables/assert_infix.rs
1//! Assert a infix operator, such as assert_infix!(a == b).
2//!
3//! Pseudocode:<br>
4//! a infix b
5//!
6//! Compare values via infix value operator:
7//!
8//! * `assert_infix!(a == b)` ≈ a == b
9//!
10//! * `assert_infix!(a != b)` ≈ a ≠ b
11//!
12//! * `assert_infix!(a < b)` ≈ a < b
13//!
14//! * `assert_infix!(a <= b)` ≈ a ≤ b
15//!
16//! * `assert_infix!(a > b)` ≈ a > b
17//!
18//! * `assert_infix!(a >= b)` ≈ a ≥ b
19//!
20//! Relate values via infix logical operator:
21//!
22//! * `assert_infix!(a & b)` ≈ a ∧ b ≈ a AND b
23//!
24//! * `assert_infix!(a | b)` ≈ a ∨ b ≈ a OR b
25//!
26//! * `assert_infix!(a ^ b)` ≈ a ⊻ b ≈ a XOR b
27//!
28//! * `assert_infix!(a && b)` ≈ a …∧ b ≈ a lazy AND b
29//!
30//! * `assert_infix!(a || b)` ≈ a …∨ b ≈ a lazy OR b
31//!
32//! # Example
33//!
34//! ```rust
35//! use assertables::*;
36//!
37//! let a = 1;
38//! let b = 1;
39//! assert_infix!(a == b);
40//! ```
41//!
42//! # Infix operators
43//!
44//! For values:
45//!
46//! * `==` equal
47//! * `!=` not equal
48//! * `<` less than
49//! * `<=` less than or equal to
50//! * `>` greater than
51//! * `>=` greater than or equal to
52//!
53//! For booleans:
54//!
55//! * `^` logical XOR
56//! * `!` logical NOT
57//! * `&` logical AND
58//! * `|` logical OR
59//! * `&&` logical lazy AND
60//! * `||` logical lazy OR
61//!
62//! # Module macros
63//!
64//! * [`assert_infix`](macro@crate::assert_infix)
65//! * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
66//! * [`debug_assert_infix`](macro@crate::debug_assert_infix)
67
68/// Assert a infix operator, such as assert_infix!(a == b).
69///
70/// Pseudocode:<br>
71/// a infix b
72///
73/// * If true, return Result `Ok(())`.
74///
75/// * Otherwise, return Result `Err(message)`.
76///
77/// This macro is useful for runtime checks, such as checking parameters,
78/// or sanitizing inputs, or handling different results in different ways.
79///
80/// # Module macros
81///
82/// * [`assert_infix`](macro@crate::assert_infix)
83/// * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
84/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
85///
86#[macro_export]
87macro_rules! assert_infix_as_result {
88 ($a:tt $infix:tt $b:tt) => {
89 if $a $infix $b {
90 Ok(())
91 } else {
92 Err(
93 format!(
94 concat!(
95 "assertion failed: `assert_infix!(a {} b)`\n",
96 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_infix.html\n",
97 " a label: `{}`,\n",
98 " a debug: `{:?}`,\n",
99 " b label: `{}`,\n",
100 " b debug: `{:?}`",
101 ),
102 stringify!($infix),
103 stringify!($a),
104 $a,
105 stringify!($b),
106 $b,
107 )
108 )
109 }
110 };
111}
112
113#[cfg(test)]
114mod test_assert_infix_as_result {
115 // use std::sync::Once;
116
117 #[test]
118 fn success() {
119 let a: i8 = 1;
120 let b: i8 = 1;
121 for _ in 0..1 {
122 let actual = assert_infix_as_result!(a == b);
123 assert_eq!(actual.unwrap(), ());
124 }
125 }
126
127 #[test]
128 fn failure() {
129 let a: i8 = 1;
130 let b: i8 = 2;
131 let actual = assert_infix_as_result!(a == b);
132 let message = concat!(
133 "assertion failed: `assert_infix!(a == b)`\n",
134 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_infix.html\n",
135 " a label: `a`,\n",
136 " a debug: `1`,\n",
137 " b label: `b`,\n",
138 " b debug: `2`",
139 );
140 assert_eq!(actual.unwrap_err(), message);
141 }
142}
143
144/// Assert a infix operator, such as assert_infix!(a == b).
145///
146/// Pseudocode:<br>
147/// a infix b
148///
149/// * If true, return `()`.
150///
151/// * Otherwise, call [`panic!`] with a message and the values of the
152/// expressions with their debug representations.
153///
154/// # Examples
155///
156/// ```rust
157/// use assertables::*;
158/// # use std::panic;
159///
160/// # fn main() {
161/// let a = 1;
162/// let b = 1;
163/// assert_infix!(a == b);
164///
165/// # let result = panic::catch_unwind(|| {
166/// // This will panic
167/// let a = 1;
168/// let b = 2;
169/// assert_infix!(a == b);
170/// # });
171/// // assertion failed: `assert_infix!(a == b)`
172/// // https://docs.rs/assertables/…/assertables/macro.assert_infix.html
173/// // a label: `a`,
174/// // a debug: `1`,
175/// // b label: `b`,
176/// // b debug: `2`
177/// # let actual = result.unwrap_err().downcast::<String>().unwrap().to_string();
178/// # let message = concat!(
179/// # "assertion failed: `assert_infix!(a == b)`\n",
180/// # "https://docs.rs/assertables/9.8.2/assertables/macro.assert_infix.html\n",
181/// # " a label: `a`,\n",
182/// # " a debug: `1`,\n",
183/// # " b label: `b`,\n",
184/// # " b debug: `2`",
185/// # );
186/// # assert_eq!(actual, message);
187/// # }
188/// ```
189///
190/// # Infix operators
191///
192/// For values:
193///
194/// * `==` equal
195/// * `!=` not equal
196/// * `<` less than
197/// * `<=` less than or equal to
198/// * `>` greater than
199/// * `>=` greater than or equal to
200///
201/// For booleans:
202///
203/// * `^` logical XOR
204/// * `!` logical NOT
205/// * `&` logical AND
206/// * `|` logical OR
207/// * `&&` logical lazy AND
208/// * `||` logical lazy OR
209///
210/// # Module macros
211///
212/// * [`assert_infix`](macro@crate::assert_infix)
213/// * [`assert_infix_as_result`](macro@crate::assert_infix_as_result)
214/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
215///
216#[macro_export]
217macro_rules! assert_infix {
218 ($a:tt $infix:tt $b:tt) => {
219 match $crate::assert_infix_as_result!($a $infix $b) {
220 Ok(()) => (),
221 Err(err) => panic!("{}", err),
222 }
223 };
224 ($a:tt $infix:tt $b:tt, $($message:tt)+) => {
225 match $crate::assert_infix_as_result!($a $infix $b) {
226 Ok(()) => (),
227 Err(err) => panic!("{}\n{}", format_args!($($message)+), err),
228 }
229 };
230}
231
232#[cfg(test)]
233mod test_assert_infix {
234 use std::panic;
235
236 #[test]
237 fn success() {
238 let a: i8 = 1;
239 let b: i8 = 1;
240 for _ in 0..1 {
241 let actual = assert_infix!(a == b);
242 assert_eq!(actual, ());
243 }
244 }
245
246 #[test]
247 fn failure() {
248 let a: i8 = 1;
249 let b: i8 = 2;
250 let result = panic::catch_unwind(|| {
251 let _actual = assert_infix!(a == b);
252 });
253 let message = concat!(
254 "assertion failed: `assert_infix!(a == b)`\n",
255 "https://docs.rs/assertables/9.8.2/assertables/macro.assert_infix.html\n",
256 " a label: `a`,\n",
257 " a debug: `1`,\n",
258 " b label: `b`,\n",
259 " b debug: `2`",
260 );
261 assert_eq!(
262 result
263 .unwrap_err()
264 .downcast::<String>()
265 .unwrap()
266 .to_string(),
267 message
268 );
269 }
270}
271
272/// Assert a infix operator, such as assert_infix!(a == b).
273///
274/// Pseudocode:<br>
275/// a infix b
276///
277/// This macro provides the same statements as [`assert_infix`](macro.assert_infix.html),
278/// except this macro's statements are only enabled in non-optimized
279/// builds by default. An optimized build will not execute this macro's
280/// statements unless `-C debug-assertions` is passed to the compiler.
281///
282/// This macro is useful for checks that are too expensive to be present
283/// in a release build but may be helpful during development.
284///
285/// The result of expanding this macro is always type checked.
286///
287/// An unchecked assertion allows a program in an inconsistent state to
288/// keep running, which might have unexpected consequences but does not
289/// introduce unsafety as long as this only happens in safe code. The
290/// performance cost of assertions, however, is not measurable in general.
291/// Replacing `assert*!` with `debug_assert*!` is thus only encouraged
292/// after thorough profiling, and more importantly, only in safe code!
293///
294/// This macro is intended to work in a similar way to
295/// [`::std::debug_assert`](https://doc.rust-lang.org/std/macro.debug_assert.html).
296///
297/// # Module macros
298///
299/// * [`assert_infix`](macro@crate::assert_infix)
300/// * [`assert_infix`](macro@crate::assert_infix)
301/// * [`debug_assert_infix`](macro@crate::debug_assert_infix)
302///
303#[macro_export]
304macro_rules! debug_assert_infix {
305 ($($arg:tt)*) => {
306 if $crate::cfg!(debug_assertions) {
307 $crate::assert_infix!($($arg)*);
308 }
309 };
310}