use std::any::Any;
use std::panic;
const ISSUE_TRACKER_URL: &str = "https://github.com/QLangstaff/qli/issues";
pub fn install() {
let default = panic::take_hook();
panic::set_hook(Box::new(move |info| {
let location = info
.location()
.map_or_else(|| "<unknown location>".to_owned(), ToString::to_string);
let message = panic_message(info.payload());
eprintln!(
"error: qli encountered an internal bug. Please report it at {ISSUE_TRACKER_URL}"
);
eprintln!(" panic at {location}: {message}");
if std::env::var_os("RUST_BACKTRACE").is_some() {
default(info);
} else {
eprintln!(" re-run with RUST_BACKTRACE=1 for a backtrace");
}
}));
}
fn panic_message(payload: &(dyn Any + Send)) -> String {
if let Some(s) = payload.downcast_ref::<&str>() {
(*s).to_owned()
} else if let Some(s) = payload.downcast_ref::<String>() {
s.clone()
} else {
"<non-string panic payload>".to_owned()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn panic_message_decodes_str_payload() {
let payload: Box<dyn Any + Send> = Box::new("hello panic");
assert_eq!(panic_message(&*payload), "hello panic");
}
#[test]
fn panic_message_decodes_string_payload() {
let payload: Box<dyn Any + Send> = Box::new(String::from("formatted panic"));
assert_eq!(panic_message(&*payload), "formatted panic");
}
#[test]
fn panic_message_handles_unknown_payload() {
#[derive(Debug)]
struct Weird;
let payload: Box<dyn Any + Send> = Box::new(Weird);
assert_eq!(panic_message(&*payload), "<non-string panic payload>");
}
}