aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_core/src')
-rw-r--r--mingling_core/src/asset/chain/error.rs16
-rw-r--r--mingling_core/src/lib.rs2
-rw-r--r--mingling_core/src/program.rs50
-rw-r--r--mingling_core/src/program/error.rs22
-rw-r--r--mingling_core/src/program/exec/error.rs5
-rw-r--r--mingling_core/src/program/hook.rs24
6 files changed, 95 insertions, 24 deletions
diff --git a/mingling_core/src/asset/chain/error.rs b/mingling_core/src/asset/chain/error.rs
index 5221e57..e5c753d 100644
--- a/mingling_core/src/asset/chain/error.rs
+++ b/mingling_core/src/asset/chain/error.rs
@@ -1,4 +1,4 @@
-use crate::error::{ProgramExecuteError, ProgramInternalExecuteError};
+use crate::error::ProgramInternalExecuteError;
#[derive(thiserror::Error, Debug)]
pub enum ChainProcessError {
@@ -9,20 +9,6 @@ pub enum ChainProcessError {
IO(#[from] std::io::Error),
}
-impl From<ProgramExecuteError> for ChainProcessError {
- fn from(value: ProgramExecuteError) -> Self {
- match value {
- ProgramExecuteError::DispatcherNotFound => {
- ChainProcessError::Other("DispatcherNotFound".into())
- }
- ProgramExecuteError::RendererNotFound(r) => {
- ChainProcessError::Other(format!("RendererNotFound: {}", r))
- }
- ProgramExecuteError::Other(e) => ChainProcessError::Other(e),
- }
- }
-}
-
impl From<ProgramInternalExecuteError> for ChainProcessError {
fn from(value: ProgramInternalExecuteError) -> Self {
match value {
diff --git a/mingling_core/src/lib.rs b/mingling_core/src/lib.rs
index 817cc7a..373df52 100644
--- a/mingling_core/src/lib.rs
+++ b/mingling_core/src/lib.rs
@@ -12,7 +12,6 @@ mod any;
mod asset;
mod program;
mod renderer;
-
mod tester;
/// Provides a toolkit for `Mingling` testing capabilities.
@@ -38,6 +37,7 @@ pub use crate::asset::renderer::*;
pub mod error {
pub use crate::asset::chain::error::*;
pub use crate::exec::error::*;
+ pub use crate::program::error::*;
#[cfg(feature = "general_renderer")]
pub use crate::renderer::general::error::*;
}
diff --git a/mingling_core/src/program.rs b/mingling_core/src/program.rs
index f2809f7..e7e9ec0 100644
--- a/mingling_core/src/program.rs
+++ b/mingling_core/src/program.rs
@@ -1,3 +1,5 @@
+use crate::error::ProgramPanic;
+
#[cfg(feature = "comp")]
use crate::{ShellContext, Suggest};
@@ -22,6 +24,8 @@ use std::{
use std::pin::Pin;
#[doc(hidden)]
+pub mod error;
+#[doc(hidden)]
pub mod exec;
#[doc(hidden)]
pub mod hook;
@@ -175,7 +179,7 @@ impl<C> Program<C>
where
C: ProgramCollect<Enum = C>,
{
- async fn exec_wrapper<F, Fut>(self, f: F) -> Fut::Output
+ async fn exec_wrapper<F, Fut>(self, f: F) -> Result<Fut::Output, ProgramPanic>
where
C: 'static + Send + Sync,
F: FnOnce(&'static Program<C>) -> Fut + Send + Sync,
@@ -189,7 +193,16 @@ where
.unwrap()
.downcast_ref::<Program<C>>()
.unwrap();
- f(program).await
+ match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(program))) {
+ Ok(fut) => Ok(fut.await),
+ Err(panic_info) => {
+ let panic_payload = ProgramPanic {
+ payload: panic_info,
+ };
+ program.run_hook_exec_panic(&panic_payload);
+ Err(panic_payload)
+ }
+ }
}
/// Run the command line program
@@ -198,8 +211,13 @@ where
C: 'static + Send + Sync,
{
self.args = self.args.iter().skip(1).cloned().collect();
- self.exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) })
+ match self
+ .exec_wrapper(|p| async { crate::exec::exec(p).await.map_err(|e| e.into()) })
.await
+ {
+ Ok(r) => r,
+ Err(e) => Err(ProgramExecuteError::Panic(e)),
+ }
}
/// Run the command line program
@@ -223,6 +241,10 @@ where
eprintln!("{}", e);
return 1;
}
+ ProgramExecuteError::Panic(unwinded_error) => {
+ eprintln!("{}", unwinded_error);
+ return 1;
+ }
},
};
@@ -259,7 +281,7 @@ impl<C> Program<C>
where
C: ProgramCollect<Enum = C>,
{
- fn exec_wrapper<F, R>(self, f: F) -> R
+ fn exec_wrapper<F, R>(self, f: F) -> Result<R, ProgramPanic>
where
C: 'static + Send + Sync,
F: FnOnce(&'static Program<C>) -> R + Send + Sync,
@@ -272,7 +294,16 @@ where
.unwrap()
.downcast_ref::<Program<C>>()
.unwrap();
- f(program)
+ match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(program))) {
+ Ok(result) => Ok(result),
+ Err(panic_info) => {
+ let panic_payload = ProgramPanic {
+ payload: panic_info,
+ };
+ program.run_hook_exec_panic(&panic_payload);
+ Err(panic_payload)
+ }
+ }
}
/// Run the command line program
@@ -281,7 +312,10 @@ where
C: 'static + Send + Sync,
{
self.args = self.args.iter().skip(1).cloned().collect();
- self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into()))
+ match self.exec_wrapper(|p| crate::exec::exec(p).map_err(|e| e.into())) {
+ Ok(r) => r,
+ Err(e) => Err(ProgramExecuteError::Panic(e)),
+ }
}
/// Run the command line program
@@ -305,6 +339,10 @@ where
eprintln!("{}", e);
return 1;
}
+ ProgramExecuteError::Panic(unwinded_error) => {
+ eprintln!("{}", unwinded_error);
+ return 1;
+ }
},
};
diff --git a/mingling_core/src/program/error.rs b/mingling_core/src/program/error.rs
new file mode 100644
index 0000000..5e92a42
--- /dev/null
+++ b/mingling_core/src/program/error.rs
@@ -0,0 +1,22 @@
+use std::any::Any;
+use std::fmt;
+use thiserror::Error;
+
+/// Error type returned when a panic occurs during execution.
+#[derive(Error)]
+#[error("execution panicked: {payload:?}")]
+pub struct ProgramPanic {
+ pub payload: Box<dyn Any + Send>,
+}
+
+impl ProgramPanic {
+ pub fn new(payload: Box<dyn Any + Send>) -> Self {
+ ProgramPanic { payload }
+ }
+}
+
+impl fmt::Debug for ProgramPanic {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.payload)
+ }
+}
diff --git a/mingling_core/src/program/exec/error.rs b/mingling_core/src/program/exec/error.rs
index b4ff378..2d806dc 100644
--- a/mingling_core/src/program/exec/error.rs
+++ b/mingling_core/src/program/exec/error.rs
@@ -1,4 +1,4 @@
-use crate::error::ChainProcessError;
+use crate::error::{ChainProcessError, ProgramPanic};
#[derive(thiserror::Error, Debug)]
pub enum ProgramExecuteError {
@@ -8,6 +8,9 @@ pub enum ProgramExecuteError {
#[error("No Renderer (`{0}`) Found")]
RendererNotFound(String),
+ #[error("Panic: {0:?}")]
+ Panic(#[from] ProgramPanic),
+
#[error("Other error: {0}")]
Other(String),
}
diff --git a/mingling_core/src/program/hook.rs b/mingling_core/src/program/hook.rs
index afc253c..080c00f 100644
--- a/mingling_core/src/program/hook.rs
+++ b/mingling_core/src/program/hook.rs
@@ -1,6 +1,6 @@
use std::any::Any;
-use crate::{AnyOutput, Program, ProgramCollect, RenderResult};
+use crate::{AnyOutput, Program, ProgramCollect, RenderResult, error::ProgramPanic};
#[derive(Default)]
pub struct ProgramHook<C>
@@ -30,6 +30,9 @@ where
/// Executes before the program ends
pub finish: Option<fn() -> i32>,
+
+ /// Executes when the program panics
+ pub exec_panic: Option<fn(&ProgramPanic)>,
}
impl<C> Program<C>
@@ -126,6 +129,18 @@ where
}
}
+ pub(crate) fn run_hook_exec_panic(&self, panic_info: &ProgramPanic) {
+ if !self.user_context.run_hook {
+ return;
+ }
+
+ for hook in &self.hooks {
+ if let Some(exec_panic) = hook.exec_panic {
+ exec_panic(panic_info)
+ }
+ }
+ }
+
pub(crate) fn run_hook_finish(&self) -> i32 {
if !self.user_context.run_hook {
return 0;
@@ -159,6 +174,7 @@ where
pre_render: None,
post_render: None,
finish: None,
+ exec_panic: None,
}
}
@@ -209,4 +225,10 @@ where
let _ = self.finish.insert(handler);
self
}
+
+ /// Sets the handler for the `exec_panic` event.
+ pub fn on_exec_panic(mut self, handler: fn(&ProgramPanic)) -> Self {
+ let _ = self.exec_panic.insert(handler);
+ self
+ }
}