use std::any::Any;
use std::error::Error;
use std::fmt;
use std::panic;
use crate::EmissionError;
#[derive(Debug)]
#[non_exhaustive]
pub enum AutoReporterError {
Emission(EmissionError),
Panicked(WorkerPanic),
}
impl From<EmissionError> for AutoReporterError {
fn from(error: EmissionError) -> Self {
Self::Emission(error)
}
}
impl fmt::Display for AutoReporterError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Emission(error) => error.fmt(formatter),
Self::Panicked(error) => error.fmt(formatter),
}
}
}
impl Error for AutoReporterError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Emission(error) => Some(error),
Self::Panicked(_) => None,
}
}
}
pub struct WorkerPanic {
payload: Box<dyn Any + Send + 'static>,
}
impl WorkerPanic {
pub(crate) fn new(payload: Box<dyn Any + Send + 'static>) -> Self {
Self { payload }
}
#[must_use]
pub fn message(&self) -> Option<&str> {
self.payload
.downcast_ref::<String>()
.map(String::as_str)
.or_else(|| self.payload.downcast_ref::<&'static str>().copied())
}
#[must_use]
pub fn into_payload(self) -> Box<dyn Any + Send + 'static> {
self.payload
}
pub fn resume_unwind(self) -> ! {
panic::resume_unwind(self.into_payload())
}
}
impl fmt::Debug for WorkerPanic {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("WorkerPanic")
.field("message", &self.message())
.finish()
}
}
impl fmt::Display for WorkerPanic {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.message() {
Some(message) => write!(
formatter,
"background reporter worker panicked: {message}"
),
None => formatter.write_str("background reporter worker panicked"),
}
}
}
impl Error for WorkerPanic {}