use std::any::Any;
const UNKNOWN: &str = "unknown panic";
pub fn panic_message(payload: &(dyn Any + Send)) -> String {
if let Some(s) = payload.downcast_ref::<String>() {
return s.clone();
}
if let Some(s) = payload.downcast_ref::<&'static str>() {
return (*s).to_string();
}
UNKNOWN.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
fn caught(f: impl FnOnce()) -> String {
let prev = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {})); let payload = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f))
.expect_err("the closure must panic");
std::panic::set_hook(prev);
panic_message(payload.as_ref())
}
#[test]
fn renders_all_three_payload_kinds() {
let formatted = "formatted message";
assert_eq!(caught(|| panic!("{formatted}")), "formatted message");
assert_eq!(caught(|| panic!("literal message")), "literal message");
assert_eq!(caught(|| std::panic::panic_any(42_i32)), UNKNOWN);
}
}