diff options
Diffstat (limited to 'ecs/src/error.rs')
| -rw-r--r-- | ecs/src/error.rs | 270 |
1 files changed, 0 insertions, 270 deletions
diff --git a/ecs/src/error.rs b/ecs/src/error.rs deleted file mode 100644 index 185b706..0000000 --- a/ecs/src/error.rs +++ /dev/null @@ -1,270 +0,0 @@ -use std::fmt::{Debug, Display, Write as _}; - -use backtrace::Backtrace; - -#[macro_export] -macro_rules! error { - ($lit: literal) => { - $crate::error::Error::from($lit) - }; - - ($lit: literal, $($tt: tt)*) => { - $crate::error::Error::from(std::format!($lit, $($tt)*)) - }; - - ($err: expr) => { - $crate::error::Error::from($err) - }; -} - -pub struct Error -{ - inner: Box<dyn std::error::Error + Send + Sync>, - backtrace: Backtrace, -} - -impl Error -{ - pub fn resolve_backtrace(&mut self) - { - self.backtrace.resolve(); - } - - fn is_backtrace_resolved(&self) -> bool - { - let Some(first_frame) = self.backtrace.frames().first() else { - return false; - }; - - !first_frame.symbols().is_empty() - } -} - -impl Debug for Error -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - let error = &*self.inner; - - write!(formatter, "{error}")?; - - if let Some(cause) = error.source() { - write!(formatter, "\n\nCaused by:")?; - let multiple = cause.source().is_some(); - for (n, error) in anyhow::Chain::new(cause).enumerate() { - writeln!(formatter)?; - - let mut indented = Indented { - inner: formatter, - number: if multiple { Some(n) } else { None }, - started: false, - }; - write!(indented, "{error}")?; - } - } - - if std::env::var_os("ENGINE_ECS_BACKTRACE") - .is_none_or(|backtrace_enabled| backtrace_enabled != "1") - { - write!( - formatter, - concat!( - "\n\nnote: run with `ENGINE_ECS_BACKTRACE=1` environment variable ", - "to display a engine backtrace" - ) - )?; - - return Ok(()); - } - - let mut cloned_backtrace; - - let backtrace = if self.is_backtrace_resolved() { - &self.backtrace - } else { - cloned_backtrace = self.backtrace.clone(); - cloned_backtrace.resolve(); - &cloned_backtrace - }; - - write!( - formatter, - "\n\nStack backtrace:\n{:?}", - std::fmt::from_fn(|backtrace_formatter| fmt_backtrace( - backtrace, - backtrace_formatter - )) - )?; - - Ok(()) - } -} - -impl Display for Error -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - let error = &*self.inner; - - write!(formatter, "{error}")?; - - if formatter.alternate() { - let chain = anyhow::Chain::new(error); - for cause in chain.skip(1) { - write!(formatter, ": {}", cause)?; - } - } - - Ok(()) - } -} - -impl<Err: Send + Sync + 'static> From<Err> for Error -where - Box<dyn std::error::Error + Send + Sync>: From<Err>, -{ - fn from(err: Err) -> Self - { - Self { - inner: err.into(), - backtrace: Backtrace::new_unresolved(), - } - } -} - -pub type ErrorHandler = fn(Error, Metadata); - -/// Error metadata. -#[derive(Debug)] -pub struct Metadata -{ - pub source_name: &'static str, - pub source_kind: SourceKind, -} - -/// Error source kind. -#[derive(Debug)] -#[non_exhaustive] -pub enum SourceKind -{ - System, - Observer, -} - -impl Display for SourceKind -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - match self { - SourceKind::System => formatter.write_str("system"), - SourceKind::Observer => formatter.write_str("observer"), - } - } -} - -pub fn err_handler_panic(mut err: Error, err_metadata: Metadata) -{ - err.resolve_backtrace(); - - panic!( - "Error occurred in {} '{}': {err:?}", - err_metadata.source_kind, err_metadata.source_name - ); -} - -pub fn err_handler_log_error(err: Error, err_metadata: Metadata) -{ - tracing::error!( - "Error occurred in {} '{}': {err:#}", - err_metadata.source_kind, - err_metadata.source_name - ); -} - -fn fmt_backtrace( - backtrace: &Backtrace, - fmt: &mut std::fmt::Formatter<'_>, -) -> std::fmt::Result -{ - let style = if fmt.alternate() { - backtrace::PrintFmt::Full - } else { - backtrace::PrintFmt::Short - }; - - // When printing paths we try to strip the cwd if it exists, otherwise - // we just print the path as-is. Note that we also only do this for the - // short format, because if it's full we presumably want to print - // everything. - let cwd = std::env::current_dir(); - let mut print_path = - move |fmt: &mut std::fmt::Formatter<'_>, - path: backtrace::BytesOrWideString<'_>| { - let path = path.into_path_buf(); - if style != backtrace::PrintFmt::Full { - if let Ok(cwd) = &cwd { - if let Ok(suffix) = path.strip_prefix(cwd) { - return std::fmt::Display::fmt(&suffix.display(), fmt); - } - } - } - std::fmt::Display::fmt(&path.display(), fmt) - }; - - let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path); - - f.add_context()?; - - for frame in backtrace.frames() { - if frame.symbols().iter().all(|symbol| { - symbol.name().is_some_and(|symbol_name| { - let symbol_name = symbol_name.to_string(); - - symbol_name - .contains("<ecs::error::Error as core::convert::From<Err>>::from") - }) - }) { - continue; - } - - f.frame().backtrace_frame(frame)?; - } - f.finish()?; - Ok(()) -} - -struct Indented<'a, D> -{ - inner: &'a mut D, - number: Option<usize>, - started: bool, -} - -impl<T> std::fmt::Write for Indented<'_, T> -where - T: std::fmt::Write, -{ - fn write_str(&mut self, s: &str) -> std::fmt::Result - { - for (i, line) in s.split('\n').enumerate() { - if !self.started { - self.started = true; - match self.number { - Some(number) => write!(self.inner, "{: >5}: ", number)?, - None => self.inner.write_str(" ")?, - } - } else if i > 0 { - self.inner.write_char('\n')?; - if self.number.is_some() { - self.inner.write_str(" ")?; - } else { - self.inner.write_str(" ")?; - } - } - - self.inner.write_str(line)?; - } - - Ok(()) - } -} |
