use core::fmt::Display;
use crate::{component::Tick, error::BevyError, prelude::Resource};
use bevy_utils::prelude::DebugName;
use derive_more::derive::{Deref, DerefMut};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ErrorContext {
System {
name: DebugName,
last_run: Tick,
},
RunCondition {
name: DebugName,
last_run: Tick,
},
Command {
name: DebugName,
},
Observer {
name: DebugName,
last_run: Tick,
},
}
impl Display for ErrorContext {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::System { name, .. } => {
write!(f, "System `{name}` failed")
}
Self::Command { name } => write!(f, "Command `{name}` failed"),
Self::Observer { name, .. } => {
write!(f, "Observer `{name}` failed")
}
Self::RunCondition { name, .. } => {
write!(f, "Run condition `{name}` failed")
}
}
}
}
impl ErrorContext {
pub fn name(&self) -> DebugName {
match self {
Self::System { name, .. }
| Self::Command { name, .. }
| Self::Observer { name, .. }
| Self::RunCondition { name, .. } => name.clone(),
}
}
pub fn kind(&self) -> &str {
match self {
Self::System { .. } => "system",
Self::Command { .. } => "command",
Self::Observer { .. } => "observer",
Self::RunCondition { .. } => "run condition",
}
}
}
macro_rules! inner {
($call:path, $e:ident, $c:ident) => {
$call!(
"Encountered an error in {} `{}`: {}",
$c.kind(),
$c.name(),
$e
);
};
}
pub type ErrorHandler = fn(BevyError, ErrorContext);
#[derive(Resource, Deref, DerefMut, Copy, Clone)]
pub struct DefaultErrorHandler(pub ErrorHandler);
impl Default for DefaultErrorHandler {
fn default() -> Self {
Self(panic)
}
}
#[track_caller]
#[inline]
pub fn panic(error: BevyError, ctx: ErrorContext) {
inner!(panic, error, ctx);
}
#[track_caller]
#[inline]
pub fn error(error: BevyError, ctx: ErrorContext) {
inner!(log::error, error, ctx);
}
#[track_caller]
#[inline]
pub fn warn(error: BevyError, ctx: ErrorContext) {
inner!(log::warn, error, ctx);
}
#[track_caller]
#[inline]
pub fn info(error: BevyError, ctx: ErrorContext) {
inner!(log::info, error, ctx);
}
#[track_caller]
#[inline]
pub fn debug(error: BevyError, ctx: ErrorContext) {
inner!(log::debug, error, ctx);
}
#[track_caller]
#[inline]
pub fn trace(error: BevyError, ctx: ErrorContext) {
inner!(log::trace, error, ctx);
}
#[track_caller]
#[inline]
pub fn ignore(_: BevyError, _: ErrorContext) {}