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}