stellar_xdr/cli/
compare.rs1use std::{
2 fmt::Debug,
3 fs::File,
4 io::{stdout, Write},
5 path::PathBuf,
6 str::FromStr,
7};
8
9use clap::{Args, ValueEnum};
10
11use crate::cli::Channel;
12
13#[derive(thiserror::Error, Debug)]
14pub enum Error {
15 #[error("unknown type {0}, choose one of {1:?}")]
16 UnknownType(String, &'static [&'static str]),
17 #[error("error decoding XDR: {0}")]
18 ReadXdrCurr(#[from] crate::curr::Error),
19 #[error("error decoding XDR: {0}")]
20 ReadXdrNext(#[from] crate::next::Error),
21 #[error("error reading file: {0}")]
22 ReadFile(std::io::Error),
23 #[error("error writing output: {0}")]
24 WriteOutput(std::io::Error),
25}
26
27#[derive(Args, Debug, Clone)]
34#[command()]
35pub struct Cmd {
36 #[arg()]
38 pub left: PathBuf,
39
40 #[arg()]
42 pub right: PathBuf,
43
44 #[arg(long)]
46 pub r#type: String,
47
48 #[arg(long, value_enum, default_value_t)]
50 pub input: InputFormat,
51}
52
53#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
54pub enum InputFormat {
55 Single,
56 SingleBase64,
57}
58
59impl Default for InputFormat {
60 fn default() -> Self {
61 Self::SingleBase64
62 }
63}
64
65macro_rules! run_x {
66 ($f:ident, $m:ident) => {
67 fn $f(&self) -> Result<(), Error> {
68 let f1 = File::open(&self.left).map_err(Error::ReadFile)?;
69 let f2 = File::open(&self.right).map_err(Error::ReadFile)?;
70 let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
71 Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR)
72 })?;
73 let (t1, t2) = match self.input {
74 InputFormat::Single => {
75 let t1 = {
76 let mut l1 = crate::$m::Limited::new(f1, crate::$m::Limits::none());
77 crate::$m::Type::read_xdr_to_end(r#type, &mut l1)?
78 };
79 let t2 = {
80 let mut l = crate::$m::Limited::new(f2, crate::$m::Limits::none());
81 crate::$m::Type::read_xdr_to_end(r#type, &mut l)?
82 };
83 (t1, t2)
84 }
85 InputFormat::SingleBase64 => {
86 let t1 = {
87 let mut l = crate::$m::Limited::new(f1, crate::$m::Limits::none());
88 crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)?
89 };
90 let t2 = {
91 let mut l = crate::$m::Limited::new(f2, crate::$m::Limits::none());
92 crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)?
93 };
94 (t1, t2)
95 }
96 };
97 let cmp = t1.cmp(&t2) as i8;
98 writeln!(stdout(), "{cmp}").map_err(Error::WriteOutput)?;
99 Ok(())
100 }
101 };
102}
103
104impl Cmd {
105 pub fn run(&self, channel: &Channel) -> Result<(), Error> {
111 let result = match channel {
112 Channel::Curr => self.run_curr(),
113 Channel::Next => self.run_next(),
114 };
115
116 match result {
117 Ok(()) => Ok(()),
118 Err(Error::WriteOutput(e)) if e.kind() == std::io::ErrorKind::BrokenPipe => Ok(()),
119 Err(e) => Err(e),
120 }
121 }
122
123 run_x!(run_curr, curr);
124 run_x!(run_next, next);
125}