1use std::process::exit;
6
7use anyhow::*;
8use async_trait::async_trait;
9
10use clap::Parser;
11use serde::Serialize;
12
13pub type CliResult = Result<String, String>;
15
16pub type CliTypedResult<T> = Result<T, Error>;
18
19#[async_trait]
21pub trait CliTool<T: Serialize + Send>: Sized + Send + Parser {
22 async fn execute(self) -> CliTypedResult<T>;
24
25 async fn execute_serialized(self) -> CliResult {
27 to_common_result(self.execute().await).await
28 }
29
30 async fn execute_serialized_success(self) -> CliResult {
32 to_common_success_result(self.execute().await).await
33 }
34
35 async fn execute_main() -> Result<()> {
37 let tool = Self::parse();
38 let result = tool.execute_serialized().await;
39 match result {
40 Result::Ok(val) => println!("{}", val),
41 Result::Err(err) => {
42 println!("{}", err);
43 exit(1);
44 }
45 };
46 Ok(())
47 }
48}
49
50pub async fn to_common_success_result<T>(result: Result<T>) -> CliResult {
52 to_common_result(result.map(|_| "Success")).await
53}
54
55#[derive(Debug, Serialize)]
72enum ResultWrapper<T> {
73 #[serde(rename = "result")]
74 Result(T),
75 #[serde(rename = "error")]
76 Error(String),
77}
78
79impl<T> From<CliTypedResult<T>> for ResultWrapper<T> {
80 fn from(result: CliTypedResult<T>) -> Self {
81 match result {
82 CliTypedResult::Ok(inner) => ResultWrapper::Result(inner),
83 CliTypedResult::Err(inner) => ResultWrapper::Error(inner.to_string()),
84 }
85 }
86}
87
88pub async fn to_common_result<T: Serialize>(result: Result<T>) -> CliResult {
90 let is_err = result.is_err();
91 let result: ResultWrapper<T> = result.into();
92 let string = serde_json::to_string_pretty(&result)
93 .map_err(|e| format!("could not serialize command output: {}", e))?;
94 if is_err {
95 CliResult::Err(string)
96 } else {
97 CliResult::Ok(string)
98 }
99}