Skip to main content

stellar_xdr/cli/generate/
default.rs

1use clap::{Args, ValueEnum};
2use std::{
3    io::{stdout, Write},
4    str::FromStr,
5};
6
7use crate::cli::util;
8
9#[derive(thiserror::Error, Debug)]
10pub enum Error {
11    #[error("unknown type {0}, choose one of {1:?}")]
12    UnknownType(String, &'static [&'static str]),
13    #[error("error reading file: {0}")]
14    ReadFile(#[from] std::io::Error),
15    #[error("error generating XDR: {0}")]
16    WriteXdr(#[from] crate::Error),
17    #[error("error generating JSON: {0}")]
18    GenerateJson(#[from] serde_json::Error),
19    #[error("type doesn't have a text representation, use 'json' as output")]
20    TextUnsupported,
21}
22
23/// Generate default XDR values
24#[derive(Args, Debug, Clone)]
25#[command()]
26pub struct Cmd {
27    /// XDR type to generate
28    #[arg(long)]
29    pub r#type: String,
30
31    // Output format to encode to
32    #[arg(long = "output", value_enum, default_value_t)]
33    pub output_format: OutputFormat,
34}
35
36#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
37pub enum OutputFormat {
38    Single,
39    SingleBase64,
40    // TODO: Stream,
41    // TODO: StreamBase64,
42    // TODO: StreamFramed,
43    Json,
44    JsonFormatted,
45    Text,
46}
47
48impl Default for OutputFormat {
49    fn default() -> Self {
50        Self::SingleBase64
51    }
52}
53
54// TODO: Remove run_x macro, it exists only to reduce the diff from when curr/next
55// channels existed and each had their own run_curr/run_next invocation.
56macro_rules! run_x {
57    ($f:ident) => {
58        fn $f(&self) -> Result<(), Error> {
59            use crate::WriteXdr;
60            let r#type = crate::TypeVariant::from_str(&self.r#type).map_err(|_| {
61                Error::UnknownType(self.r#type.clone(), &crate::TypeVariant::VARIANTS_STR)
62            })?;
63            let v = crate::Type::default(r#type);
64            match self.output_format {
65                OutputFormat::Single => {
66                    let l = crate::Limits::none();
67                    stdout().write_all(&v.to_xdr(l)?)?
68                }
69                OutputFormat::SingleBase64 => {
70                    let l = crate::Limits::none();
71                    println!("{}", v.to_xdr_base64(l)?)
72                }
73                OutputFormat::Json => {
74                    println!("{}", serde_json::to_string(&v)?);
75                }
76                OutputFormat::JsonFormatted => {
77                    println!("{}", serde_json::to_string_pretty(&v)?);
78                }
79                OutputFormat::Text => {
80                    let v = serde_json::to_value(v)?;
81                    let text = util::serde_json_value_to_text(v).ok_or(Error::TextUnsupported)?;
82                    println!("{text}")
83                }
84            }
85            Ok(())
86        }
87    };
88}
89
90impl Cmd {
91    /// Run the CLIs generate zero command.
92    ///
93    /// ## Errors
94    ///
95    /// If the command is configured with state that is invalid.
96    pub fn run(&self) -> Result<(), Error> {
97        self.run_inner()
98    }
99
100    run_x!(run_inner);
101}