stellar_xdr/cli/generate/
arbitrary.rs1use arbitrary::Unstructured;
2use clap::{Args, ValueEnum};
3use std::{
4 io::{stdout, Write},
5 str::FromStr,
6};
7
8use crate::cli::util;
9
10#[derive(thiserror::Error, Debug)]
11pub enum Error {
12 #[error("unknown type {0}, choose one of {1:?}")]
13 UnknownType(String, &'static [&'static str]),
14 #[error("error reading file: {0}")]
15 ReadFile(#[from] std::io::Error),
16 #[error("error generating XDR: {0}")]
17 WriteXdr(#[from] crate::Error),
18 #[error("error generating JSON: {0}")]
19 GenerateJson(#[from] serde_json::Error),
20 #[error("error generating arbitrary value: {0}")]
21 Arbitrary(#[from] arbitrary::Error),
22 #[error("type doesn't have a text representation, use 'json' as output")]
23 TextUnsupported,
24}
25
26#[derive(Args, Debug, Clone)]
28#[command()]
29pub struct Cmd {
30 #[arg(long)]
32 pub r#type: String,
33
34 #[arg(long = "output", value_enum, default_value_t)]
36 pub output_format: OutputFormat,
37}
38
39#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
40pub enum OutputFormat {
41 Single,
42 SingleBase64,
43 Json,
47 JsonFormatted,
48 Text,
49}
50
51impl Default for OutputFormat {
52 fn default() -> Self {
53 Self::SingleBase64
54 }
55}
56
57macro_rules! run_x {
60 ($f:ident) => {
61 fn $f(&self) -> Result<(), Error> {
62 use crate::WriteXdr;
63 let r#type = crate::TypeVariant::from_str(&self.r#type).map_err(|_| {
64 Error::UnknownType(self.r#type.clone(), &crate::TypeVariant::VARIANTS_STR)
65 })?;
66 let r = rand::random::<[u8; 10_240]>();
67 let mut u = Unstructured::new(&r);
68 let v = crate::Type::arbitrary(r#type, &mut u)?;
69 match self.output_format {
70 OutputFormat::Single => {
71 let l = crate::Limits::none();
72 stdout().write_all(&v.to_xdr(l)?)?
73 }
74 OutputFormat::SingleBase64 => {
75 let l = crate::Limits::none();
76 println!("{}", v.to_xdr_base64(l)?)
77 }
78 OutputFormat::Json => {
79 println!("{}", serde_json::to_string(&v)?);
80 }
81 OutputFormat::JsonFormatted => {
82 println!("{}", serde_json::to_string_pretty(&v)?);
83 }
84 OutputFormat::Text => {
85 let v = serde_json::to_value(v)?;
86 let text = util::serde_json_value_to_text(v).ok_or(Error::TextUnsupported)?;
87 println!("{text}")
88 }
89 }
90 Ok(())
91 }
92 };
93}
94
95impl Cmd {
96 pub fn run(&self) -> Result<(), Error> {
102 self.run_inner()
103 }
104
105 run_x!(run_inner);
106}