Vendor always-assert

This commit is contained in:
Lukas Wirth 2025-02-24 14:00:16 +01:00
parent 6d68c475c7
commit 9a462b7c36
5 changed files with 122 additions and 8 deletions

View file

@ -94,7 +94,7 @@ syntax-bridge.workspace = true
[features]
jemalloc = ["jemallocator", "profile/jemalloc"]
force-always-assert = ["always-assert/force"]
force-always-assert = ["stdx/force-always-assert"]
sysroot-abi = []
in-rust-tree = [
"sysroot-abi",

View file

@ -14,11 +14,11 @@ doctest = false
[dependencies]
backtrace = { version = "0.3.67", optional = true }
always-assert = { version = "0.2.0", features = ["tracing"] }
jod-thread = "0.1.2"
libc.workspace = true
crossbeam-channel.workspace = true
itertools.workspace = true
tracing.workspace = true
# Think twice before adding anything here
[target.'cfg(windows)'.dependencies]
@ -28,6 +28,7 @@ windows-sys = { version = "0.59", features = ["Win32_Foundation"] }
[features]
# Uncomment to enable for the whole crate graph
# default = [ "backtrace" ]
force-always-assert = []
[lints]
workspace = true

115
crates/stdx/src/assert.rs Normal file
View file

@ -0,0 +1,115 @@
// Vendored from https://github.com/matklad/always-assert/commit/4cf564eea6fcf18b30c3c3483a611004dc03afbb
//! Recoverable assertions, inspired by [the use of `assert()` in
//! SQLite](https://www.sqlite.org/assert.html).
//!
//! `never!` and `always!` return the actual value of the condition if
//! `debug_assertions` are disabled.
//!
//! Use them when terminating on assertion failure is worse than continuing.
//!
//! One example would be a critical application like a database:
//!
//! ```ignore
//! use stdx::never;
//!
//! fn apply_transaction(&mut self, tx: Transaction) -> Result<(), TransactionAborted> {
//! let delta = self.compute_delta(&tx);
//!
//! if never!(!self.check_internal_invariant(&delta)) {
//! // Ok, something in this transaction messed up our internal state.
//! // This really shouldn't be happening, and this signifies a bug.
//! // Luckily, we can recover by just rejecting the transaction.
//! return abort_transaction(tx);
//! }
//! self.commit(delta);
//! Ok(())
//! }
//! ```
//!
//! Another example is assertions about non-critical functionality in usual apps
//!
//! ```ignore
//! use stdx::never;
//!
//! let english_message = "super app installed!"
//! let mut local_message = localize(english_message);
//! if never!(local_message.is_empty(), "missing localization for {}", english_message) {
//! // We localized all the messages but this one slipper through the cracks?
//! // Better to show the english one then than to fail outright;
//! local_message = english_message;
//! }
//! println!("{}", local_message);
//! ```
/// Asserts that the condition is always true and returns its actual value.
///
/// If the condition is true does nothing and and evaluates to true.
///
/// If the condition is false:
/// * panics if `force` feature or `debug_assertions` are enabled,
/// * logs an error if the `tracing` feature is enabled,
/// * evaluates to false.
///
/// Accepts `format!` style arguments.
#[macro_export]
macro_rules! always {
($cond:expr) => {
$crate::always!($cond, "assertion failed: {}", stringify!($cond))
};
($cond:expr, $fmt:literal $($arg:tt)*) => {{
let cond = $cond;
if cfg!(debug_assertions) || $crate::assert::__FORCE {
assert!(cond, $fmt $($arg)*);
}
if !cond {
$crate::assert::__tracing_error!($fmt $($arg)*);
}
cond
}};
}
/// Asserts that the condition is never true and returns its actual value.
///
/// If the condition is false does nothing and and evaluates to false.
///
/// If the condition is true:
/// * panics if `force` feature or `debug_assertions` are enabled,
/// * logs an error if the `tracing` feature is enabled,
/// * evaluates to true.
///
/// Accepts `format!` style arguments.
///
/// Empty condition is equivalent to false:
///
/// ```ignore
/// never!("oups") ~= unreachable!("oups")
/// ```
#[macro_export]
macro_rules! never {
(true $($tt:tt)*) => { $crate::never!((true) $($tt)*) };
(false $($tt:tt)*) => { $crate::never!((false) $($tt)*) };
() => { $crate::never!("assertion failed: entered unreachable code") };
($fmt:literal $(, $($arg:tt)*)?) => {{
if cfg!(debug_assertions) || $crate::assert::__FORCE {
unreachable!($fmt $(, $($arg)*)?);
}
$crate::assert::__tracing_error!($fmt $(, $($arg)*)?);
}};
($cond:expr) => {{
let cond = !$crate::always!(!$cond);
cond
}};
($cond:expr, $fmt:literal $($arg:tt)*) => {{
let cond = !$crate::always!(!$cond, $fmt $($arg)*);
cond
}};
}
#[doc(hidden)]
pub use tracing::error as __tracing_error;
#[doc(hidden)]
pub const __FORCE: bool = cfg!(feature = "force-always-assert");

View file

@ -4,8 +4,10 @@ use std::io as sio;
use std::process::Command;
use std::{cmp::Ordering, ops, time::Instant};
pub mod anymap;
mod macros;
pub mod anymap;
pub mod assert;
pub mod non_empty_vec;
pub mod panic_context;
pub mod process;
@ -13,7 +15,6 @@ pub mod rand;
pub mod thin_vec;
pub mod thread;
pub use always_assert::{always, never};
pub use itertools;
#[inline(always)]