aboutsummaryrefslogtreecommitdiff
path: root/mingling_core/src/program/once_exec.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_core/src/program/once_exec.rs')
-rw-r--r--mingling_core/src/program/once_exec.rs235
1 files changed, 235 insertions, 0 deletions
diff --git a/mingling_core/src/program/once_exec.rs b/mingling_core/src/program/once_exec.rs
new file mode 100644
index 0000000..ac985e2
--- /dev/null
+++ b/mingling_core/src/program/once_exec.rs
@@ -0,0 +1,235 @@
+use crate::THIS_PROGRAM;
+use crate::{
+ Program, ProgramCollect, RenderResult,
+ error::{ProgramExecuteError, ProgramPanic},
+};
+
+// Async program
+#[cfg(feature = "async")]
+impl<C> Program<C>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ 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,
+ Fut: Future + Send,
+ {
+ THIS_PROGRAM.get_or_init(|| Some(Box::new(self)));
+ let program = THIS_PROGRAM
+ .get()
+ .unwrap()
+ .as_ref()
+ .unwrap()
+ .downcast_ref::<Program<C>>()
+ .unwrap();
+
+ #[cfg(not(panic = "abort"))]
+ if program.stdout_setting.silence_panic {
+ std::panic::set_hook(Box::new(|_| {}));
+ }
+
+ #[cfg(panic = "abort")]
+ return Ok(f(program));
+
+ #[cfg(not(panic = "abort"))]
+ 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
+ pub async fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError>
+ where
+ C: 'static + Send + Sync,
+ {
+ // Run hooks
+ self.run_hook_on_begin();
+
+ self.args = self.args.iter().skip(1).cloned().collect();
+ 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
+ pub async fn exec(self) -> i32
+ where
+ C: 'static + Send + Sync,
+ {
+ let stdout_setting = self.stdout_setting.clone();
+ let result = match self.exec_without_render().await {
+ Ok(r) => r,
+ Err(e) => match e {
+ ProgramExecuteError::DispatcherNotFound => {
+ eprintln!("Dispatcher not found");
+ return 1;
+ }
+ ProgramExecuteError::RendererNotFound(renderer_name) => {
+ eprintln!("Renderer `{}` not found", renderer_name);
+ return 1;
+ }
+ ProgramExecuteError::Other(e) => {
+ eprintln!("{}", e);
+ return 1;
+ }
+ ProgramExecuteError::Panic(unwinded_error) => {
+ eprintln!("{}", unwinded_error);
+ return 1;
+ }
+ },
+ };
+
+ // Render result
+ if stdout_setting.render_output && !result.is_empty() {
+ let exit_code = result.exit_code;
+ print!("{}", result);
+
+ if let Err(e) = std::io::Write::flush(&mut std::io::stdout())
+ && stdout_setting.error_output
+ {
+ eprintln!("{}", e);
+ 1
+ } else {
+ exit_code
+ }
+ } else {
+ 0
+ }
+ }
+
+ /// Run the command line program, then exit
+ pub async fn exec_and_exit(self)
+ where
+ C: 'static + Send + Sync,
+ {
+ std::process::exit(self.exec().await)
+ }
+}
+
+// Sync program
+#[cfg(not(feature = "async"))]
+impl<C> Program<C>
+where
+ C: ProgramCollect<Enum = C>,
+{
+ fn exec_wrapper<F, R>(self, f: F) -> Result<R, ProgramPanic>
+ where
+ C: 'static + Send + Sync,
+ F: FnOnce(&'static Program<C>) -> R + Send + Sync,
+ {
+ THIS_PROGRAM.get_or_init(|| Some(Box::new(self)));
+ let program = THIS_PROGRAM
+ .get()
+ .unwrap()
+ .as_ref()
+ .unwrap()
+ .downcast_ref::<Program<C>>()
+ .unwrap();
+
+ #[cfg(not(panic = "abort"))]
+ if program.stdout_setting.silence_panic {
+ std::panic::set_hook(Box::new(|_| {}));
+ }
+
+ #[cfg(panic = "abort")]
+ return Ok(f(program));
+
+ #[cfg(not(panic = "abort"))]
+ match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(program))) {
+ Ok(result) => Ok(result),
+ Err(panic_info) => {
+ use crate::error::ProgramPanic;
+
+ let panic_payload = ProgramPanic {
+ payload: panic_info,
+ };
+ program.run_hook_exec_panic(&panic_payload);
+ Err(panic_payload)
+ }
+ }
+ }
+
+ /// Run the command line program
+ pub fn exec_without_render(mut self) -> Result<RenderResult, ProgramExecuteError>
+ where
+ C: 'static + Send + Sync,
+ {
+ // Run hooks
+ self.run_hook_on_begin();
+
+ self.args = self.args.iter().skip(1).cloned().collect();
+ 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
+ pub fn exec(self) -> i32
+ where
+ C: 'static + Send + Sync,
+ {
+ use crate::error::ProgramExecuteError;
+
+ let stdout_setting = self.stdout_setting.clone();
+ let result = match self.exec_without_render() {
+ Ok(r) => r,
+ Err(e) => match e {
+ ProgramExecuteError::DispatcherNotFound => {
+ eprintln!("Dispatcher not found");
+ return 1;
+ }
+ ProgramExecuteError::RendererNotFound(renderer_name) => {
+ eprintln!("Renderer `{}` not found", renderer_name);
+ return 1;
+ }
+ ProgramExecuteError::Other(e) => {
+ eprintln!("{}", e);
+ return 1;
+ }
+ ProgramExecuteError::Panic(unwinded_error) => {
+ eprintln!("{}", unwinded_error);
+ return 1;
+ }
+ },
+ };
+
+ // Render result
+ if stdout_setting.render_output && !result.is_empty() {
+ let exit_code = result.exit_code;
+ print!("{}", result);
+
+ if let Err(e) = std::io::Write::flush(&mut std::io::stdout())
+ && stdout_setting.error_output
+ {
+ eprintln!("{}", e);
+ 1
+ } else {
+ exit_code
+ }
+ } else {
+ 0
+ }
+ }
+
+ /// Run the command line program, then exit
+ pub fn exec_and_exit(self)
+ where
+ C: 'static + Send + Sync,
+ {
+ std::process::exit(self.exec())
+ }
+}