From 929cf7f315d6863cd7a8d7814f2ed5fa19adede5 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sun, 29 Sep 2024 14:41:24 +1000 Subject: [PATCH 1/3] Add compare sub-command to cli --- src/bin/stellar-xdr/main.rs | 3 +- src/cli/compare.rs | 108 ++++++++++++++++++++++++++++++++++++ src/cli/mod.rs | 6 ++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/cli/compare.rs diff --git a/src/bin/stellar-xdr/main.rs b/src/bin/stellar-xdr/main.rs index 2873708b..fdfdcef3 100644 --- a/src/bin/stellar-xdr/main.rs +++ b/src/bin/stellar-xdr/main.rs @@ -9,7 +9,8 @@ fn main() { cli::Error::Types(_) | cli::Error::Guess(_) | cli::Error::Decode(_) - | cli::Error::Encode(_) => { + | cli::Error::Encode(_) + | cli::Error::Compare(_) => { Error::raw(clap::error::ErrorKind::ValueValidation, e).exit() } } diff --git a/src/cli/compare.rs b/src/cli/compare.rs new file mode 100644 index 00000000..a5d0b1a8 --- /dev/null +++ b/src/cli/compare.rs @@ -0,0 +1,108 @@ +use std::{fmt::Debug, fs::File, path::PathBuf, str::FromStr}; + +use clap::{Args, ValueEnum}; + +use crate::cli::{skip_whitespace::SkipWhitespace, Channel}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("unknown type {0}, choose one of {1:?}")] + UnknownType(String, &'static [&'static str]), + #[error("error decoding XDR: {0}")] + ReadXdrCurr(#[from] crate::curr::Error), + #[error("error decoding XDR: {0}")] + ReadXdrNext(#[from] crate::next::Error), + #[error("error reading file: {0}")] + ReadFile(#[from] std::io::Error), +} + +#[derive(Args, Debug, Clone)] +#[command()] +pub struct Cmd { + /// First XDR to decode and compare with the second file + #[arg()] + file1: PathBuf, + + /// Second XDR to decode and compare with the second file + #[arg()] + file2: PathBuf, + + /// XDR type of both inputs + #[arg(long)] + r#type: String, + + // Input format of the XDR + #[arg(long, value_enum, default_value_t)] + input: InputFormat, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)] +pub enum InputFormat { + Single, + SingleBase64, +} + +impl Default for InputFormat { + fn default() -> Self { + Self::SingleBase64 + } +} + +macro_rules! run_x { + ($f:ident, $m:ident) => { + fn $f(&self) -> Result<(), Error> { + let f1 = File::open(&self.file1)?; + let f2 = File::open(&self.file2)?; + let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| { + Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR) + })?; + let (t1, t2) = match self.input { + InputFormat::Single => { + let t1 = { + let mut l1 = crate::$m::Limited::new(f1, crate::$m::Limits::none()); + crate::$m::Type::read_xdr_to_end(r#type, &mut l1)? + }; + let t2 = { + let mut l = crate::$m::Limited::new(f2, crate::$m::Limits::none()); + crate::$m::Type::read_xdr_to_end(r#type, &mut l)? + }; + (t1, t2) + } + InputFormat::SingleBase64 => { + let t1 = { + let sw = SkipWhitespace::new(f1); + let mut l = crate::$m::Limited::new(sw, crate::$m::Limits::none()); + crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)? + }; + let t2 = { + let sw = SkipWhitespace::new(f2); + let mut l = crate::$m::Limited::new(sw, crate::$m::Limits::none()); + crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)? + }; + (t1, t2) + } + }; + let cmp = t1.cmp(&t2) as i8; + println!("{cmp}"); + Ok(()) + } + }; +} + +impl Cmd { + /// Run the CLIs decode command. + /// + /// ## Errors + /// + /// If the command is configured with state that is invalid. + pub fn run(&self, channel: &Channel) -> Result<(), Error> { + match channel { + Channel::Curr => self.run_curr()?, + Channel::Next => self.run_next()?, + } + Ok(()) + } + + run_x!(run_curr, curr); + run_x!(run_next, next); +} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6128be04..b7fb1ef9 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,3 +1,4 @@ +pub mod compare; pub mod decode; pub mod encode; pub mod guess; @@ -39,6 +40,7 @@ impl Root { Cmd::Guess(c) => c.run(&self.channel)?, Cmd::Decode(c) => c.run(&self.channel)?, Cmd::Encode(c) => c.run(&self.channel)?, + Cmd::Compare(c) => c.run(&self.channel)?, Cmd::Version => version::Cmd::run(), } Ok(()) @@ -69,6 +71,8 @@ pub enum Cmd { Decode(decode::Cmd), /// Encode XDR Encode(encode::Cmd), + /// Compare XDR + Compare(compare::Cmd), /// Print version information Version, } @@ -86,6 +90,8 @@ pub enum Error { Decode(#[from] decode::Error), #[error("error reading file: {0}")] Encode(#[from] encode::Error), + #[error(transparent)] + Compare(#[from] compare::Error), } /// Run the CLI with the given args. From f7138f8334862df47ab1d58a2ad4b6f357d5bc74 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sun, 29 Sep 2024 22:21:52 +1000 Subject: [PATCH 2/3] tweak --- src/cli/compare.rs | 18 ++++++++++++------ src/cli/mod.rs | 1 - 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/cli/compare.rs b/src/cli/compare.rs index a5d0b1a8..79c1c75e 100644 --- a/src/cli/compare.rs +++ b/src/cli/compare.rs @@ -16,16 +16,22 @@ pub enum Error { ReadFile(#[from] std::io::Error), } +/// Compare two XDR values with each other +/// +/// Outputs: +/// - `-1` when the left XDR value is less than the right XDR value +/// - `0` when the left XDR value is equal to the right XDR value +/// - `1` when the left XDR value is greater than the right XDR value #[derive(Args, Debug, Clone)] #[command()] pub struct Cmd { - /// First XDR to decode and compare with the second file + /// XDR file to decode and compare with the right value #[arg()] - file1: PathBuf, + left: PathBuf, - /// Second XDR to decode and compare with the second file + /// XDR file to decode and compare with the left value #[arg()] - file2: PathBuf, + right: PathBuf, /// XDR type of both inputs #[arg(long)] @@ -51,8 +57,8 @@ impl Default for InputFormat { macro_rules! run_x { ($f:ident, $m:ident) => { fn $f(&self) -> Result<(), Error> { - let f1 = File::open(&self.file1)?; - let f2 = File::open(&self.file2)?; + let f1 = File::open(&self.left)?; + let f2 = File::open(&self.right)?; let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| { Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR) })?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index b7fb1ef9..ef64e159 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -71,7 +71,6 @@ pub enum Cmd { Decode(decode::Cmd), /// Encode XDR Encode(encode::Cmd), - /// Compare XDR Compare(compare::Cmd), /// Print version information Version, From 3cf023d1f2b8eed532c697501d063cb24064b9e7 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Sun, 29 Sep 2024 22:47:41 +1000 Subject: [PATCH 3/3] fix --- src/cli/compare.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/compare.rs b/src/cli/compare.rs index 79c1c75e..55b195c6 100644 --- a/src/cli/compare.rs +++ b/src/cli/compare.rs @@ -19,9 +19,9 @@ pub enum Error { /// Compare two XDR values with each other /// /// Outputs: -/// - `-1` when the left XDR value is less than the right XDR value -/// - `0` when the left XDR value is equal to the right XDR value -/// - `1` when the left XDR value is greater than the right XDR value +/// `-1` when the left XDR value is less than the right XDR value, +/// `0` when the left XDR value is equal to the right XDR value, +/// `1` when the left XDR value is greater than the right XDR value #[derive(Args, Debug, Clone)] #[command()] pub struct Cmd {