custom_print/macros/panic_hook.rs
1/// Defines `panic_hook` function that can be used as panic hook that uses the specified writer.
2///
3/// The first argument specify function name in the format `fn FUNC_NAME(...)`
4/// and can be omitted to use the default name `panic_hook`.
5///
6/// # Examples
7///
8#[cfg_attr(feature = "alloc", doc = "```rust")]
9#[cfg_attr(not(feature = "alloc"), doc = "```rust,compile_fail")]
10/// use once_cell::sync::Lazy;
11/// use std::sync::Mutex;
12///
13/// static MESSAGE: Lazy<Mutex<String>> = Lazy::new(Mutex::default);
14///
15/// fn main() {
16/// use std::panic::{catch_unwind, take_hook};
17///
18/// fn write(value: &str) {
19/// let mut chunks = MESSAGE.lock().unwrap();
20/// *chunks += value;
21/// }
22///
23/// custom_print::define_panic_hook!(concat, write);
24/// std::panic::set_hook(Box::new(panic_hook));
25///
26/// let result = catch_unwind(|| assert_eq!("foo", "bar"));
27/// let _ = take_hook();
28/// assert!(result.is_err());
29/// let message = MESSAGE.lock().unwrap();
30///
31/// assert!(message.contains("panicked"));
32/// assert!(message.contains("assertion failed"));
33/// assert!(message.contains("\"foo\""));
34/// assert!(message.contains("\"bar\""));
35/// }
36/// ```
37#[macro_export]
38macro_rules! define_panic_hook {
39 ( $(#[$extern_meta:meta])* $vis:vis fn $name:ident(...), $($args:tt)* ) => {
40 $(#[$extern_meta])*
41 $vis fn $name(info: &::std::panic::PanicInfo<'_>) {
42 ::core::writeln!($crate::define_writer!($($args)*), "{}", info)
43 .expect("failed writing panic info");
44 }
45 };
46 ( $($args:tt)* ) => {
47 $crate::define_panic_hook!(fn panic_hook(...), $($args)*);
48 };
49}
50
51/// Defines `init_panic_hook` function that set panic hook with the specified writer.
52///
53/// The first argument specify function name in the format `fn FUNC_NAME()`
54/// and can be omitted to use the default name `init_panic_hook`.
55///
56#[cfg_attr(feature = "alloc", doc = "```rust")]
57#[cfg_attr(not(feature = "alloc"), doc = "```rust,compile_fail")]
58/// use once_cell::sync::Lazy;
59/// use std::sync::Mutex;
60///
61/// static MESSAGE: Lazy<Mutex<String>> = Lazy::new(Mutex::default);
62///
63/// fn main() {
64/// use std::panic::{catch_unwind, take_hook};
65///
66/// fn write(value: &str) {
67/// let mut chunks = MESSAGE.lock().unwrap();
68/// *chunks += value;
69/// }
70///
71/// custom_print::define_init_panic_hook!(concat, write);
72/// init_panic_hook();
73///
74/// let result = catch_unwind(|| assert_eq!("foo", "bar"));
75/// let _ = take_hook();
76/// assert!(result.is_err());
77/// let message = MESSAGE.lock().unwrap();
78///
79/// assert!(message.contains("panicked"));
80/// assert!(message.contains("assertion failed"));
81/// assert!(message.contains("\"foo\""));
82/// assert!(message.contains("\"bar\""));
83/// }
84/// ```
85#[macro_export]
86macro_rules! define_init_panic_hook {
87 ( $(#[$extern_meta:meta])* $vis:vis fn $name:ident(), $($args:tt)* ) => {
88 $(#[$extern_meta])*
89 $vis fn $name() {
90 ::std::panic::set_hook(::std::boxed::Box::new(
91 |info: &::std::panic::PanicInfo<'_>| {
92 ::core::writeln!($crate::define_writer!($($args)*), "{}", info)
93 .expect("failed writing panic info");
94 }
95 ))
96 }
97 };
98 ( $($args:tt)* ) => {
99 $crate::define_init_panic_hook!(fn init_panic_hook(), $($args)*);
100 };
101}
102
103/// Sets `panic_hook` that uses the specified writer.
104///
105/// # Examples
106///
107#[cfg_attr(feature = "alloc", doc = "```rust")]
108#[cfg_attr(not(feature = "alloc"), doc = "```rust,compile_fail")]
109/// use once_cell::sync::Lazy;
110/// use std::sync::Mutex;
111///
112/// static MESSAGE: Lazy<Mutex<String>> = Lazy::new(Mutex::default);
113///
114/// fn main() {
115/// use std::panic::{catch_unwind, take_hook};
116///
117/// fn write(value: &str) {
118/// let mut chunks = MESSAGE.lock().unwrap();
119/// *chunks += value;
120/// }
121///
122/// custom_print::init_panic_hook!(concat, write);
123///
124/// let result = catch_unwind(|| assert_eq!("foo", "bar"));
125/// let _ = take_hook();
126/// assert!(result.is_err());
127/// let message = MESSAGE.lock().unwrap();
128///
129/// assert!(message.contains("panicked"));
130/// assert!(message.contains("assertion failed"));
131/// assert!(message.contains("\"foo\""));
132/// assert!(message.contains("\"bar\""));
133/// }
134/// ```
135#[macro_export]
136macro_rules! init_panic_hook {
137 ( $($args:tt)* ) => {
138 ::std::panic::set_hook(::std::boxed::Box::new(
139 |info: &::std::panic::PanicInfo<'_>| {
140 ::core::writeln!($crate::define_writer!($($args)*), "{}", info)
141 .expect("failed writing panic info");
142 }
143 ))
144 };
145}