]> git.lizzy.rs Git - rust.git/blob - crates/stdx/src/macros.rs
4f5c6100d2a860b085239e263f27750bafbee8ea
[rust.git] / crates / stdx / src / macros.rs
1 //! Convenience macros.
2
3 use std::{
4     fmt, mem, panic,
5     sync::atomic::{AtomicUsize, Ordering::SeqCst},
6 };
7 #[macro_export]
8 macro_rules! eprintln {
9     ($($tt:tt)*) => {{
10         if $crate::is_ci() {
11             panic!("Forgot to remove debug-print?")
12         }
13         std::eprintln!($($tt)*)
14     }}
15 }
16
17 /// Appends formatted string to a `String`.
18 #[macro_export]
19 macro_rules! format_to {
20     ($buf:expr) => ();
21     ($buf:expr, $lit:literal $($arg:tt)*) => {
22         { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
23     };
24 }
25
26 /// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums
27 ///
28 /// # Example
29 ///
30 /// ```rust
31 /// impl_from!(Struct, Union, Enum for Adt);
32 /// ```
33 #[macro_export]
34 macro_rules! impl_from {
35     ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => {
36         $(
37             impl From<$variant> for $enum {
38                 fn from(it: $variant) -> $enum {
39                     $enum::$variant(it)
40                 }
41             }
42             $($(
43                 impl From<$sub_variant> for $enum {
44                     fn from(it: $sub_variant) -> $enum {
45                         $enum::$variant($variant::$sub_variant(it))
46                     }
47                 }
48             )*)?
49         )*
50     }
51 }
52
53 /// A version of `assert!` macro which allows to handle an assertion failure.
54 ///
55 /// In release mode, it returns the condition and logs an error.
56 ///
57 /// ```
58 /// if assert_never!(impossible) {
59 ///     // Heh, this shouldn't have happened, but lets try to soldier on...
60 ///     return None;
61 /// }
62 /// ```
63 ///
64 /// Rust analyzer is a long-running process, and crashing really isn't an option.
65 ///
66 /// Shamelessly stolen from: https://www.sqlite.org/assert.html
67 #[macro_export]
68 macro_rules! assert_never {
69     ($cond:expr) => { $crate::assert_never!($cond, "") };
70     ($cond:expr, $($fmt:tt)*) => {{
71         let value = $cond;
72         if value {
73             $crate::on_assert_failure(
74                 format_args!($($fmt)*)
75             );
76         }
77         value
78     }};
79 }
80
81 type AssertHook = fn(&panic::Location<'_>, fmt::Arguments<'_>);
82 static HOOK: AtomicUsize = AtomicUsize::new(0);
83
84 pub fn set_assert_hook(hook: AssertHook) {
85     HOOK.store(hook as usize, SeqCst);
86 }
87
88 #[cold]
89 #[track_caller]
90 pub fn on_assert_failure(args: fmt::Arguments) {
91     let hook: usize = HOOK.load(SeqCst);
92     if hook == 0 {
93         panic!("\n  assertion failed: {}\n", args);
94     }
95
96     let hook: AssertHook = unsafe { mem::transmute::<usize, AssertHook>(hook) };
97     hook(panic::Location::caller(), args)
98 }