#[rustversion::since(1.81)]
type PanicHookInfo<'a> = std::panic::PanicHookInfo<'a>;
#[rustversion::before(1.81)]
type PanicHookInfo<'a> = std::panic::PanicInfo<'a>;
pub fn panic_hook(panic_info: &PanicHookInfo) {
let panic_info_indented = format!("{panic_info}")
.lines()
.map(|x| format!("{:indent$}{x}", "", indent = 4))
.collect::<Vec<String>>()
.join("\n");
#[cfg(debug_assertions)]
let bt = get_backtrace();
#[cfg(not(debug_assertions))]
let bt = " (Backtrace is not available on the release build)";
crate::io::r_eprint(
&format!(
"panic occured!
Original message:
{panic_info_indented}
Backtrace:
{bt}
"
),
true,
);
}
#[cfg(debug_assertions)]
fn get_backtrace() -> String {
let show_full = if let Ok(v) = std::env::var("RUST_BACKTRACE") {
&v == "1"
} else {
false
};
let bt = std::backtrace::Backtrace::force_capture().to_string();
if !show_full {
let bt_short = bt
.lines()
.skip_while(|line| !line.contains("std::panic::catch_unwind"))
.take_while(|line| !line.contains("<unknown>"))
.map(|x| format!("{:indent$}{x}", "", indent = 4))
.collect::<Vec<String>>()
.join("\n");
if !bt_short.is_empty() {
return format!(
" ...
{bt_short}
...
note: Run with `RUST_BACKTRACE=1` for a full backtrace.
"
);
}
}
bt.lines()
.map(|x| format!("{:indent$}{x}", "", indent = 4))
.collect::<Vec<String>>()
.join("\n")
}