stdx/
assert.rs

1// Vendored from https://github.com/matklad/always-assert/commit/4cf564eea6fcf18b30c3c3483a611004dc03afbb
2//! Recoverable assertions, inspired by [the use of `assert()` in
3//! SQLite](https://www.sqlite.org/assert.html).
4//!
5//! `never!` and `always!` return the actual value of the condition if
6//! `debug_assertions` are disabled.
7//!
8//! Use them when terminating on assertion failure is worse than continuing.
9//!
10//! One example would be a critical application like a database:
11//!
12//! ```ignore
13//! use stdx::never;
14//!
15//! fn apply_transaction(&mut self, tx: Transaction) -> Result<(), TransactionAborted> {
16//!     let delta = self.compute_delta(&tx);
17//!
18//!     if never!(!self.check_internal_invariant(&delta)) {
19//!         // Ok, something in this transaction messed up our internal state.
20//!         // This really shouldn't be happening, and this signifies a bug.
21//!         // Luckily, we can recover by just rejecting the transaction.
22//!         return abort_transaction(tx);
23//!     }
24//!     self.commit(delta);
25//!     Ok(())
26//! }
27//! ```
28//!
29//! Another example is assertions about non-critical functionality in usual apps
30//!
31//! ```ignore
32//! use stdx::never;
33//!
34//! let english_message = "super app installed!"
35//! let mut local_message = localize(english_message);
36//! if never!(local_message.is_empty(), "missing localization for {}", english_message) {
37//!     // We localized all the messages but this one slipper through the cracks?
38//!     // Better to show the english one then than to fail outright;
39//!     local_message = english_message;
40//! }
41//! println!("{}", local_message);
42//! ```
43
44/// Asserts that the condition is always true and returns its actual value.
45///
46/// If the condition is true does nothing and and evaluates to true.
47///
48/// If the condition is false:
49/// * panics if `force` feature or `debug_assertions` are enabled,
50/// * logs an error if the `tracing` feature is enabled,
51/// * evaluates to false.
52///
53/// Accepts `format!` style arguments.
54#[macro_export]
55macro_rules! always {
56    ($cond:expr) => {
57        $crate::always!($cond, "assertion failed: {}", stringify!($cond))
58    };
59
60    ($cond:expr, $fmt:literal $($arg:tt)*) => {{
61        let cond = $cond;
62        if cfg!(debug_assertions) || $crate::assert::__FORCE {
63            assert!(cond, $fmt $($arg)*);
64        }
65        if !cond {
66            $crate::assert::__tracing_error!($fmt $($arg)*);
67        }
68        cond
69    }};
70}
71
72/// Asserts that the condition is never true and returns its actual value.
73///
74/// If the condition is false does nothing and and evaluates to false.
75///
76/// If the condition is true:
77/// * panics if `force` feature or `debug_assertions` are enabled,
78/// * logs an error if the `tracing` feature is enabled,
79/// * evaluates to true.
80///
81/// Accepts `format!` style arguments.
82///
83/// Empty condition is equivalent to false:
84///
85/// ```ignore
86/// never!("oups") ~= unreachable!("oups")
87/// ```
88#[macro_export]
89macro_rules! never {
90    (true $($tt:tt)*) => { $crate::never!((true) $($tt)*) };
91    (false $($tt:tt)*) => { $crate::never!((false) $($tt)*) };
92    () => { $crate::never!("assertion failed: entered unreachable code") };
93    ($fmt:literal $(, $($arg:tt)*)?) => {{
94        if cfg!(debug_assertions) || $crate::assert::__FORCE {
95            unreachable!($fmt $(, $($arg)*)?);
96        }
97        $crate::assert::__tracing_error!($fmt $(, $($arg)*)?);
98    }};
99
100    ($cond:expr) => {{
101        let cond = !$crate::always!(!$cond);
102        cond
103    }};
104
105    ($cond:expr, $fmt:literal $($arg:tt)*) => {{
106        let cond = !$crate::always!(!$cond, $fmt $($arg)*);
107        cond
108    }};
109}
110
111#[doc(hidden)]
112pub use tracing::error as __tracing_error;
113
114#[doc(hidden)]
115pub const __FORCE: bool = cfg!(feature = "force-always-assert");