more_asserts/
lib.rs

1//! Small library providing some macros helpful for asserting. The API is very
2//! similar to the API provided by the stdlib's own
3//! [`assert_eq!`](core::assert_eq), [`assert_ne!`](core::assert_ne),
4//! [`debug_assert_eq!`](core::debug_assert_eq), and
5//! [`debug_assert_ne!`](core::debug_assert_ne).
6//!
7//! | Name                 | Enabled                       | Equivalent to                                |
8//! | -------------------- | ----------------------------- | -------------------------------------------- |
9//! | `assert_le!`         | Always                        | `assert!(a <= b)`                            |
10//! | `assert_lt!`         | Always                        | `assert!(a < b)`                             |
11//! | `assert_ge!`         | Always                        | `assert!(a >= b)`                            |
12//! | `assert_gt!`         | Always                        | `assert!(a > b)`                             |
13//! | `debug_assert_le!`   | `if cfg!(debug_assertions)`   | `debug_assert!(a <= b)`                      |
14//! | `debug_assert_lt!`   | `if cfg!(debug_assertions)`   | `debug_assert!(a < b)`                       |
15//! | `debug_assert_ge!`   | `if cfg!(debug_assertions)`   | `debug_assert!(a >= b)`                      |
16//! | `debug_assert_gt!`   | `if cfg!(debug_assertions)`   | `debug_assert!(a > b)`                       |
17//! | `debug_unreachable!` | `if cfg!(debug_assertions)`   | `unreachable!` when debug_assertions are on. |
18//!
19//! When one of the assertions fails, it prints out a message like the
20//! following:
21//!
22//! ```text
23//! thread 'main' panicked at 'assertion failed: `left < right`
24//!   left: `4`,
25//!  right: `3`', src/main.rs:47:5
26//! note: Run with `RUST_BACKTRACE=1` for a backtrace.
27//! ```
28//!
29//! # Example
30//!
31//! ```rust
32//! use more_asserts as ma;
33//!
34//! #[derive(Debug, PartialEq, PartialOrd)]
35//! enum Example { Foo, Bar }
36//!
37//! ma::assert_le!(3, 4);
38//! ma::assert_ge!(
39//!     10, 10,
40//!     "You can pass a message too (just like `assert_eq!`)",
41//! );
42//! ma::debug_assert_lt!(
43//!     1.3, 4.5,
44//!     "Format syntax is supported ({}).",
45//!     "also like `assert_eq!`"
46//! );
47//!
48//! ma::assert_gt!(
49//!     Example::Bar, Example::Foo,
50//!     "It works on anything that implements PartialOrd and Debug!",
51//! );
52//! ```
53#![no_std]
54#![deny(missing_docs)]
55
56mod inner;
57
58// From use with macros. Not public API.
59#[doc(hidden)]
60pub extern crate core as __core;
61
62// From use with macros. Not public API.
63#[doc(hidden)]
64pub mod __private {
65    pub use crate::inner::AssertType;
66    // Wrap the outlined functions with generic versions in an effort to improve
67    // the error message given when using one of these macros on a type which
68    // doesn't impl `core::fmt::Debug`.
69    #[cold]
70    #[track_caller]
71    pub fn assert_failed_nomsg<A, B>(left: &A, right: &B, ty: AssertType) -> !
72    where
73        A: core::fmt::Debug,
74        B: core::fmt::Debug,
75    {
76        crate::inner::assert_failed_nomsg_impl(left, right, ty);
77    }
78
79    #[cold]
80    #[track_caller]
81    #[doc(hidden)]
82    pub fn assert_failed_msg<A, B>(
83        left: &A,
84        right: &B,
85        ty: AssertType,
86        msg: core::fmt::Arguments<'_>,
87    ) -> !
88    where
89        A: core::fmt::Debug,
90        B: core::fmt::Debug,
91    {
92        crate::inner::assert_failed_msg_impl(left, right, ty, msg);
93    }
94}
95
96/// Panics if the first expression is not strictly less than the second.
97///
98/// Requires that the values implement [`Debug`](core::fmt::Debug) and
99/// [`PartialOrd`](core::cmp::PartialOrd).
100///
101/// On failure, panics and prints the values out in a manner similar to
102/// [`assert_eq!`](core::assert_eq).
103///
104/// # Example
105///
106/// ```rust
107/// use more_asserts as ma;
108///
109/// ma::assert_lt!(3, 4);
110/// ma::assert_lt!(3, 4, "With a message");
111/// ma::assert_lt!(3, 4, "With a formatted message: {}", "oh no");
112/// ```
113#[macro_export]
114macro_rules! assert_lt {
115    ($left:expr, $right:expr) => {
116        match (&$left, &$right) {
117            (left, right) => if !(left < right) {
118                $crate::__private::assert_failed_nomsg(
119                    left, right, $crate::__private::AssertType::Lt,
120                );
121            }
122        }
123    };
124    ($left:expr, $right:expr, ) => {
125        $crate::assert_lt!($left, $right)
126    };
127    ($left:expr, $right:expr, $($msg_args:tt)+) => {
128        match (&$left, &$right) {
129            (left, right) => if !(left < right) {
130                $crate::__private::assert_failed_msg(
131                    left, right, $crate::__private::AssertType::Lt,
132                    $crate::__core::format_args!($($msg_args)+),
133                );
134            }
135        }
136    };
137}
138
139/// Panics if the first expression is not strictly greater than the second.
140///
141/// Requires that the values implement [`Debug`](core::fmt::Debug) and
142/// [`PartialOrd`](core::cmp::PartialOrd).
143///
144/// On failure, panics and prints the values out in a manner similar to
145/// prelude's [`assert_eq!`](core::assert_eq).
146///
147/// # Example
148///
149/// ```rust
150/// use more_asserts as ma;
151///
152/// ma::assert_gt!(5, 3);
153/// ma::assert_gt!(5, 3, "With a message");
154/// ma::assert_gt!(5, 3, "With a formatted message: {}", "oh no");
155/// ```
156#[macro_export]
157macro_rules! assert_gt {
158    ($left:expr, $right:expr) => {
159        match (&$left, &$right) {
160            (left, right) => if !(left > right) {
161                $crate::__private::assert_failed_nomsg(
162                    left, right, $crate::__private::AssertType::Gt,
163                );
164            }
165        }
166    };
167    ($left:expr, $right:expr, ) => {
168        $crate::assert_gt!($left, $right)
169    };
170    ($left:expr, $right:expr, $($msg_args:tt)+) => {
171        match (&$left, &$right) {
172            (left, right) => if !(left > right) {
173                $crate::__private::assert_failed_msg(
174                    left, right, $crate::__private::AssertType::Gt,
175                    $crate::__core::format_args!($($msg_args)+),
176                );
177            }
178        }
179    };
180}
181
182/// Panics if the first expression is not less than or equal to the second.
183///
184/// Requires that the values implement [`Debug`](core::fmt::Debug) and
185/// [`PartialOrd`](core::cmp::PartialOrd).
186///
187/// On failure, panics and prints the values out in a manner similar to
188/// prelude's [`assert_eq!`](core::assert_eq).
189///
190/// # Example
191///
192/// ```rust
193/// use more_asserts as ma;
194///
195/// ma::assert_le!(4, 4);
196/// ma::assert_le!(4, 5);
197/// ma::assert_le!(4, 5, "With a message");
198/// ma::assert_le!(4, 4, "With a formatted message: {}", "oh no");
199/// ```
200#[macro_export]
201macro_rules! assert_le {
202    ($left:expr, $right:expr) => {
203        match (&$left, &$right) {
204            (left, right) => if !(left <= right) {
205                $crate::__private::assert_failed_nomsg(
206                    left, right, $crate::__private::AssertType::Le,
207                );
208            }
209        }
210    };
211    ($left:expr, $right:expr, ) => {
212        $crate::assert_le!($left, $right)
213    };
214    ($left:expr, $right:expr, $($msg_args:tt)+) => {
215        match (&$left, &$right) {
216            (left, right) => if !(left <= right) {
217                $crate::__private::assert_failed_msg(
218                    left, right, $crate::__private::AssertType::Le,
219                    $crate::__core::format_args!($($msg_args)+),
220                );
221            }
222        }
223    };
224}
225
226/// Panics if the first expression is not greater than or equal to the second.
227///
228/// Requires that the values implement [`Debug`](core::fmt::Debug) and
229/// [`PartialOrd`](core::cmp::PartialOrd).
230///
231/// On failure, panics and prints the values out in a manner similar to
232/// prelude's [`assert_eq!`](core::assert_eq).
233///
234/// Optionally may take an additional message to display on failure, which is
235/// formatted using standard format syntax.
236///
237/// # Example
238///
239/// ```rust
240/// use more_asserts as ma;
241///
242/// ma::assert_ge!(4, 4);
243/// ma::assert_ge!(4, 3);
244/// ma::assert_ge!(4, 3, "With a message");
245/// ma::assert_ge!(4, 4, "With a formatted message: {}", "oh no");
246/// ```
247#[macro_export]
248macro_rules! assert_ge {
249    ($left:expr, $right:expr) => {
250        match (&$left, &$right) {
251            (left, right) => if !(left >= right) {
252                $crate::__private::assert_failed_nomsg(
253                    left, right, $crate::__private::AssertType::Ge,
254                );
255            }
256        }
257    };
258    ($left:expr, $right:expr, ) => {
259        $crate::assert_ge!($left, $right)
260    };
261    ($left:expr, $right:expr, $($msg_args:tt)+) => {
262        match (&$left, &$right) {
263            (left, right) => if !(left >= right) {
264                $crate::__private::assert_failed_msg(
265                    left, right, $crate::__private::AssertType::Ge,
266                    $crate::__core::format_args!($($msg_args)+),
267                );
268            }
269        }
270    };
271}
272
273/// Same as [`assert_lt!`] in builds with debug assertions enabled, and a no-op
274/// otherwise.
275///
276/// # Example
277///
278/// ```rust
279/// use more_asserts as ma;
280///
281/// // These are compiled to nothing if debug_assertions are off!
282/// ma::debug_assert_lt!(3, 4);
283/// ma::debug_assert_lt!(3, 4, "With a message");
284/// ma::debug_assert_lt!(3, 4, "With a formatted message: {}", "oh no");
285/// ```
286#[macro_export]
287macro_rules! debug_assert_lt {
288    ($($arg:tt)+) => {
289        if $crate::__core::cfg!(debug_assertions) {
290            $crate::assert_lt!($($arg)+);
291        }
292    };
293}
294
295/// Same as [`assert_gt!`] in builds with debug assertions enabled, and a no-op
296/// otherwise.
297///
298/// # Example
299///
300/// ```rust
301/// use more_asserts as ma;
302///
303/// // These are compiled to nothing if debug_assertions are off!
304/// ma::debug_assert_gt!(5, 3);
305/// ma::debug_assert_gt!(5, 3, "With a message");
306/// ma::debug_assert_gt!(5, 3, "With a formatted message: {}", "oh no");
307/// ```
308#[macro_export]
309macro_rules! debug_assert_gt {
310    ($($arg:tt)+) => {
311        if $crate::__core::cfg!(debug_assertions) {
312            $crate::assert_gt!($($arg)+);
313        }
314    };
315}
316
317/// Same as [`assert_le!`] in builds with debug assertions enabled, and a no-op
318/// otherwise.
319///
320/// # Example
321///
322/// ```rust
323/// use more_asserts as ma;
324///
325/// // These are compiled to nothing if debug_assertions are off!
326/// ma::debug_assert_le!(4, 4);
327/// ma::debug_assert_le!(4, 5);
328/// ma::debug_assert_le!(4, 5, "With a message");
329/// ma::debug_assert_le!(4, 4, "With a formatted message: {}", "oh no");
330/// ```
331#[macro_export]
332macro_rules! debug_assert_le {
333    ($($arg:tt)+) => {
334        if $crate::__core::cfg!(debug_assertions) {
335            $crate::assert_le!($($arg)+);
336        }
337    };
338}
339
340/// Same as [`assert_ge!`] in builds with debug assertions enabled, and a no-op
341/// otherwise.
342///
343/// # Example
344///
345/// ```rust
346/// use more_asserts as ma;
347///
348/// // These are compiled to nothing if debug_assertions are off!
349/// ma::debug_assert_ge!(4, 4);
350/// ma::debug_assert_ge!(4, 3);
351/// ma::debug_assert_ge!(4, 3, "With a message");
352/// ma::debug_assert_ge!(4, 4, "With a formatted message: {}", "oh no");
353/// ```
354#[macro_export]
355macro_rules! debug_assert_ge {
356    ($($arg:tt)+) => {
357        if $crate::__core::cfg!(debug_assertions) {
358            $crate::assert_ge!($($arg)+);
359        }
360    };
361}
362
363/// Panics if reached when debug assertions are enabled.
364///
365/// This is a variant of the standard library's [`unreachable!`] macro that is
366/// controlled by `cfg!(debug_assertions)`. For builds without debug assertions
367/// enabled (such as typical release builds), it is a no-op.
368///
369/// # Example
370///
371/// ```rust
372/// use more_asserts as ma;
373///
374/// let mut value = 0.5;
375/// if value < 0.0 {
376///     ma::debug_unreachable!("Value out of range {}", value);
377///     value = 0.0;
378/// }
379/// ```
380#[macro_export]
381macro_rules! debug_unreachable {
382    ($($arg:tt)*) => {
383        if $crate::__core::cfg!(debug_assertions) {
384            $crate::__core::unreachable!($($arg)*);
385        }
386    };
387}