summaryrefslogtreecommitdiff
path: root/ecs/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/error.rs')
-rw-r--r--ecs/src/error.rs270
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(())
- }
-}