1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
use serde::Serialize;
use crate::{
r_println,
systems::cmd::{
errors::{CmdExecuteError, CmdPrepareError, CmdProcessError, CmdRenderError},
renderer::{JVRenderResult, JVResultRenderer},
},
};
use std::future::Future;
pub struct JVCommandContext {
pub help: bool,
pub confirmed: bool,
}
pub trait JVCommand<Argument, Input, Collect, Output, Renderer>
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(
args: Vec<String>,
ctx: JVCommandContext,
renderer: String,
) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
where
Self: Sync,
{
async move {
let renderer_str = renderer.as_str();
include!("_renderers.rs")
}
}
/// performing any necessary post-execution processing
fn process(
args: Vec<String>,
ctx: JVCommandContext,
) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
where
Self: Sync,
{
Self::process_with_renderer::<Renderer>(args, ctx)
}
/// Process the command output with a custom renderer,
/// performing any necessary post-execution processing
fn process_with_renderer<R: JVResultRenderer<Output> + Send>(
args: Vec<String>,
ctx: JVCommandContext,
) -> impl Future<Output = Result<JVRenderResult, CmdProcessError>> + Send
where
Self: Sync,
{
async move {
let mut full_args = vec!["jv".to_string()];
full_args.extend(args);
let parsed_args = match Argument::try_parse_from(full_args) {
Ok(args) => args,
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)
) {
Ok((input, collect)) => (input, collect),
Err(e) => return Err(CmdProcessError::from(e)),
};
let output = 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)),
}
}
}
/// Prepare
/// Converts Argument input into parameters readable during the execution phase
fn prepare(
args: &Argument,
ctx: &JVCommandContext,
) -> impl Future<Output = Result<Input, CmdPrepareError>> + Send;
/// Resource collection
/// Reads required resources and sends them to the `exec` function
fn collect(
args: &Argument,
ctx: &JVCommandContext,
) -> impl Future<Output = Result<Collect, CmdPrepareError>> + Send;
/// Execute
/// Executes the results obtained from `prepare` and `collect`
/// Returns data that can be used for rendering
fn exec(
input: Input,
collect: Collect,
) -> impl Future<Output = Result<Output, CmdExecuteError>> + Send;
}
|