summaryrefslogtreecommitdiff
path: root/src/systems/cmd/cmd_system.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-02-04 00:27:16 +0800
committer魏曹先生 <1992414357@qq.com>2026-02-04 00:27:16 +0800
commitd19e5d84ee21502fd3440511d4ffb1ee1f49d3b2 (patch)
treefb8efef6f8e9a26c5b60d4ac220b11d6c6f0775e /src/systems/cmd/cmd_system.rs
parent7ee0d3f20c875e7405bb8442c5eb0228d1599a03 (diff)
Refactor build system and implement complete renderer system
- Split monolithic build.rs into modular async generators - Add renderer override system with type-safe dispatch - Implement command template macro for consistent command definitions - Add proc-macro crates for command and renderer systems - Reorganize directory structure for better separation of concerns - Update documentation to reflect new architecture
Diffstat (limited to 'src/systems/cmd/cmd_system.rs')
-rw-r--r--src/systems/cmd/cmd_system.rs106
1 files changed, 62 insertions, 44 deletions
diff --git a/src/systems/cmd/cmd_system.rs b/src/systems/cmd/cmd_system.rs
index 20f5aef..030e711 100644
--- a/src/systems/cmd/cmd_system.rs
+++ b/src/systems/cmd/cmd_system.rs
@@ -1,64 +1,88 @@
-use serde::Serialize;
-
use crate::{
r_println,
- systems::cmd::{
- errors::{CmdExecuteError, CmdPrepareError, CmdProcessError, CmdRenderError},
- renderer::{JVRenderResult, JVResultRenderer},
+ systems::{
+ cmd::errors::{CmdExecuteError, CmdPrepareError, CmdProcessError, CmdRenderError},
+ render::{render_system::render, renderer::JVRenderResult},
},
};
-use std::future::Future;
+use std::{
+ any::{Any, TypeId},
+ collections::HashMap,
+ future::Future,
+};
pub struct JVCommandContext {
pub help: bool,
pub confirmed: bool,
}
-pub trait JVCommand<Argument, Input, Collect, Output, Renderer>
+pub trait JVCommand<Argument, Input, Collect>
where
Argument: clap::Parser + Send,
Input: Send,
- Output: Serialize + Send + Sync,
Collect: Send,
- Renderer: JVResultRenderer<Output> + Send + Sync,
{
/// Get help string for the command
fn get_help_str() -> String;
- /// Process the command with a specified renderer, performing any necessary post-execution processing
- fn process_with_renderer_flag(
+ /// Run the command and convert the result into type-agnostic serialized information,
+ /// then hand it over to the universal renderer for rendering.
+ /// Universal renderer: uses the renderer specified by the `--renderer` flag.
+ fn process_to_renderer_override(
args: Vec<String>,
ctx: JVCommandContext,
- renderer: String,
- ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
- where
- Self: Sync,
- {
+ renderer_override: String,
+ ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send {
async move {
- let renderer_str = renderer.as_str();
- include!("_renderers.rs")
+ // If the `--help` flag is used,
+ // skip execution and return an error,
+ // unlike `process_to_render_system`,
+ // when the `--renderer` flag specifies a renderer, `--help` output is not allowed
+ if ctx.help {
+ return Err(CmdProcessError::RendererOverrideButRequestHelp);
+ }
+
+ let (data, type_name) = Self::process(args, ctx).await?;
+
+ let renderer_override = renderer_override.as_str();
+
+ // Serialize the data based on its concrete type
+ let render_result = include!("../render/_override_renderer_entry.rs");
+
+ match render_result {
+ Ok(r) => Ok(r),
+ Err(e) => Err(CmdProcessError::Render(e)),
+ }
}
}
- /// performing any necessary post-execution processing
- fn process(
+ /// Run the command and hand it over to the rendering system
+ /// to select the appropriate renderer for the result
+ fn process_to_render_system(
args: Vec<String>,
ctx: JVCommandContext,
- ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
- where
- Self: Sync,
- {
- Self::process_with_renderer::<Renderer>(args, ctx)
+ ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send {
+ async {
+ // If the `--help` flag is used,
+ // skip execution and directly render help information
+ if ctx.help {
+ let mut r = JVRenderResult::default();
+ r_println!(r, "{}", Self::get_help_str());
+ return Ok(r);
+ }
+
+ let (data, id_str) = Self::process(args, ctx).await?;
+ match render(data, id_str).await {
+ Ok(r) => Ok(r),
+ Err(e) => Err(CmdProcessError::Render(e)),
+ }
+ }
}
- /// Process the command output with a custom renderer,
- /// performing any necessary post-execution processing
- fn process_with_renderer<R: JVResultRenderer<Output> + Send>(
+ fn process(
args: Vec<String>,
ctx: JVCommandContext,
- ) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
- where
- Self: Sync,
+ ) -> impl Future<Output = Result<(Box<dyn Any + Send + 'static>, String), CmdProcessError>> + Send
{
async move {
let mut full_args = vec!["jv".to_string()];
@@ -70,13 +94,6 @@ where
Err(_) => return Err(CmdProcessError::ParseError(Self::get_help_str())),
};
- // If the help flag is used, skip execution and directly print help
- if ctx.help {
- let mut r = JVRenderResult::default();
- r_println!(r, "{}", Self::get_help_str());
- return Ok(r);
- }
-
let (input, collect) = match tokio::try_join!(
Self::prepare(&parsed_args, &ctx),
Self::collect(&parsed_args, &ctx)
@@ -85,17 +102,15 @@ where
Err(e) => return Err(CmdProcessError::from(e)),
};
- let output = match Self::exec(input, collect).await {
+ let data = match Self::exec(input, collect).await {
Ok(output) => output,
Err(e) => return Err(CmdProcessError::from(e)),
};
- match R::render(&output).await {
- Ok(r) => Ok(r),
- Err(e) => Err(CmdProcessError::from(e)),
- }
+ Ok(data)
}
}
+
/// Prepare
/// Converts Argument input into parameters readable during the execution phase
fn prepare(
@@ -116,5 +131,8 @@ where
fn exec(
input: Input,
collect: Collect,
- ) -> impl Future<Output = Result<Output, CmdExecuteError>> + Send;
+ ) -> impl Future<Output = Result<(Box<dyn Any + Send + 'static>, String), CmdExecuteError>> + Send;
+
+ /// Get output type mapping
+ fn get_output_type_mapping() -> HashMap<String, TypeId>;
}