#![no_std]
#![warn(missing_docs)]
#![allow(clippy::style)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
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,
}
}
#[derive(Clone, Copy, Debug)]
pub struct PanicDetails<'a, M: 'a> {
pub location: &'a Location<'a>,
pub message: M,
}
impl<M: Message> core::error::Error for PanicDetails<'_, M> {
}
impl<M: Message> fmt::Display for PanicDetails<'_, M> {
#[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)
}
}
pub trait PanicInfoExt<'a> {
fn panic_message(&'a self) -> impl Message + 'a;
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a, impl Message + 'a> {
PanicDetails {
location: Location::caller(),
message: self.panic_message(),
}
}
}
impl<'a> PanicInfoExt<'a> for PanicInfo<'a> {
#[inline(always)]
fn panic_message(&'a self) -> impl Message + 'a {
self.message()
}
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a, impl Message + 'a> {
let location = match self.location() {
Some(location) => location,
None => Location::caller(),
};
PanicDetails {
location,
message: self.panic_message()
}
}
}
impl<'a> PanicInfoExt<'a> for &'a (dyn core::any::Any + Send + 'static) {
#[inline(always)]
fn panic_message(&'a self) -> impl Message + 'a {
downcast_payload(*self)
}
}
#[cfg(feature = "alloc")]
impl<'a> PanicInfoExt<'a> for alloc::boxed::Box<dyn core::any::Any + Send + 'static> {
#[inline(always)]
fn panic_message(&'a self) -> impl Message + 'a {
downcast_payload(self)
}
}
#[cfg(feature = "std")]
impl<'a> PanicInfoExt<'a> for std::panic::PanicHookInfo<'a> {
#[inline(always)]
fn panic_message(&'a self) -> impl Message + 'a {
downcast_payload(self.payload())
}
#[track_caller]
#[inline(always)]
fn panic_details(&'a self) -> PanicDetails<'a, impl Message + 'a> {
let location = match self.location() {
Some(location) => location,
None => Location::caller(),
};
PanicDetails {
location,
message: self.panic_message()
}
}
}