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, Channel};
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 WriteXdrCurr(crate::curr::Error),
18 #[error("error generating XDR: {0}")]
19 WriteXdrNext(crate::next::Error),
20 #[error("error generating JSON: {0}")]
21 GenerateJson(#[from] serde_json::Error),
22 #[error("error generating arbitrary value: {0}")]
23 Arbitrary(#[from] arbitrary::Error),
24 #[error("type doesn't have a text representation, use 'json' as output")]
25 TextUnsupported,
26}
27
28impl From<crate::curr::Error> for Error {
29 fn from(e: crate::curr::Error) -> Self {
30 match e {
31 crate::curr::Error::Invalid
32 | crate::curr::Error::Unsupported
33 | crate::curr::Error::LengthExceedsMax
34 | crate::curr::Error::LengthMismatch
35 | crate::curr::Error::NonZeroPadding
36 | crate::curr::Error::Utf8Error(_)
37 | crate::curr::Error::InvalidHex
38 | crate::curr::Error::Io(_)
39 | crate::curr::Error::DepthLimitExceeded
40 | crate::curr::Error::LengthLimitExceeded
41 | crate::curr::Error::Arbitrary(_)
42 | crate::curr::Error::Json(_) => Error::WriteXdrCurr(e),
43 }
44 }
45}
46
47impl From<crate::next::Error> for Error {
48 fn from(e: crate::next::Error) -> Self {
49 match e {
50 crate::next::Error::Invalid
51 | crate::next::Error::Unsupported
52 | crate::next::Error::LengthExceedsMax
53 | crate::next::Error::LengthMismatch
54 | crate::next::Error::NonZeroPadding
55 | crate::next::Error::Utf8Error(_)
56 | crate::next::Error::InvalidHex
57 | crate::next::Error::Io(_)
58 | crate::next::Error::DepthLimitExceeded
59 | crate::next::Error::LengthLimitExceeded
60 | crate::next::Error::Arbitrary(_)
61 | crate::next::Error::Json(_) => Error::WriteXdrNext(e),
62 }
63 }
64}
65
66#[derive(Args, Debug, Clone)]
68#[command()]
69pub struct Cmd {
70 #[arg(long)]
72 pub r#type: String,
73
74 #[arg(long = "output", value_enum, default_value_t)]
76 pub output_format: OutputFormat,
77}
78
79#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
80pub enum OutputFormat {
81 Single,
82 SingleBase64,
83 Json,
87 JsonFormatted,
88 Text,
89}
90
91impl Default for OutputFormat {
92 fn default() -> Self {
93 Self::SingleBase64
94 }
95}
96
97macro_rules! run_x {
98 ($f:ident, $m:ident) => {
99 fn $f(&self) -> Result<(), Error> {
100 use crate::$m::WriteXdr;
101 let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
102 Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR)
103 })?;
104 let r = rand::random::<[u8; 10_240]>();
105 let mut u = Unstructured::new(&r);
106 let v = crate::$m::Type::arbitrary(r#type, &mut u)?;
107 match self.output_format {
108 OutputFormat::Single => {
109 let l = crate::$m::Limits::none();
110 stdout().write_all(&v.to_xdr(l)?)?
111 }
112 OutputFormat::SingleBase64 => {
113 let l = crate::$m::Limits::none();
114 println!("{}", v.to_xdr_base64(l)?)
115 }
116 OutputFormat::Json => {
117 println!("{}", serde_json::to_string(&v)?);
118 }
119 OutputFormat::JsonFormatted => {
120 println!("{}", serde_json::to_string_pretty(&v)?);
121 }
122 OutputFormat::Text => {
123 let v = serde_json::to_value(v)?;
124 let text = util::serde_json_value_to_text(v).ok_or(Error::TextUnsupported)?;
125 println!("{text}")
126 }
127 }
128 Ok(())
129 }
130 };
131}
132
133impl Cmd {
134 pub fn run(&self, channel: &Channel) -> Result<(), Error> {
140 match channel {
141 Channel::Curr => self.run_curr()?,
142 Channel::Next => self.run_next()?,
143 }
144 Ok(())
145 }
146
147 run_x!(run_curr, curr);
148 run_x!(run_next, next);
149}