#![no_std]
#![warn(missing_docs)]
#![allow(clippy::style)]
#[cfg(feature = "alloc")]
extern crate alloc;
use core::fmt;
use core::panic::{Location, PanicInfo};
pub trait Message: fmt::Display + fmt::Debug {}
impl<T: fmt::Display + fmt::Debug> Message for T {}
#[inline(always)]
pub fn downcast_payload<'a>(payload: &'a (dyn core::any::Any + Send + 'static)) -> &'a dyn Message {
const DEFAULT_MESSAGE: &'static str = "panic occurred";
match payload.downcast_ref::<&'static str>() {
Some(message) => message,
#[cfg(feature = "alloc")]
None => match payload.downcast_ref::<alloc::string::String>() {
Some(message) => message,
None => &DEFAULT_MESSAGE,
},
#[cfg(not(feature = "alloc"))]
None => &DEFAULT_MESSAGE,
}
}
#[inline(always)]
pub fn get_message<'a>(panic: &'a PanicInfo<'a>) -> &'a dyn Message {
downcast_payload(panic.payload())
}
#[derive(Clone, Copy, Debug)]
pub struct PanicDetails<'a> {
pub location: &'a Location<'a>,
pub message: &'a dyn Message,
}
pub trait PanicInfoExt<'a> {
fn panic_details(&'a self) -> PanicDetails<'a>;
}
impl<'a> PanicInfoExt<'a> for PanicInfo<'a> {
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a> {
let location = match self.location() {
Some(location) => location,
None => Location::caller(),
};
PanicDetails {
location,
message: get_message(self),
}
}
}
impl<'a> PanicInfoExt<'a> for &'a (dyn core::any::Any + Send + 'static) {
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a> {
PanicDetails {
location: Location::caller(),
message: downcast_payload(*self),
}
}
}
#[cfg(feature = "alloc")]
impl<'a> PanicInfoExt<'a> for alloc::boxed::Box<dyn core::any::Any + Send + 'static> {
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a> {
PanicDetails {
location: Location::caller(),
message: downcast_payload(self),
}
}
}
impl fmt::Display for PanicDetails<'_> {
#[inline(always)]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.location, fmt)?;
fmt.write_str(": ")?;
fmt::Display::fmt(self.message, fmt)
}
}