Skip to content

Commit

Permalink
Add encode subcommand to cli (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmcculloch authored Oct 18, 2023
1 parent b7102b5 commit b96ca71
Show file tree
Hide file tree
Showing 6 changed files with 3,322 additions and 2 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ next = []
# Features dependent on optional dependencies.
base64 = ["std", "dep:base64"]
serde = ["alloc", "dep:serde", "dep:serde_with", "hex/serde"]
serde_json = ["serde", "dep:serde_json"]
arbitrary = ["std", "dep:arbitrary"]
hex = []

# Features for the CLI.
cli = ["std", "curr", "next", "base64", "serde", "dep:clap", "dep:serde_json", "dep:thiserror"]
cli = ["std", "curr", "next", "base64", "serde", "serde_json", "dep:clap", "dep:thiserror"]

[package.metadata.docs.rs]
all-features = true
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export RUSTFLAGS=-Dwarnings -Dclippy::all -Dclippy::pedantic

CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features base64,serde,arbitrary,hex

XDRGEN_VERSION=96e91ce
XDRGEN_VERSION=92e5c651
CARGO_DOC_ARGS?=--open

all: build test
Expand Down
159 changes: 159 additions & 0 deletions src/bin/stellar-xdr/encode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use std::{
fs::File,
io::{stdin, stdout, Read, Write},
path::PathBuf,
str::FromStr,
};

use clap::{Args, ValueEnum};

use crate::Channel;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("unknown type {0}, choose one of {1:?}")]
UnknownType(String, &'static [&'static str]),
#[error("error decoding JSON: {0}")]
ReadJsonCurr(stellar_xdr::curr::Error),
#[error("error decoding JSON: {0}")]
ReadJsonNext(stellar_xdr::next::Error),
#[error("error reading file: {0}")]
ReadFile(#[from] std::io::Error),
#[error("error generating XDR: {0}")]
WriteXdrCurr(stellar_xdr::curr::Error),
#[error("error generating XDR: {0}")]
WriteXdrNext(stellar_xdr::next::Error),
}

impl From<stellar_xdr::curr::Error> for Error {
fn from(e: stellar_xdr::curr::Error) -> Self {
match e {
stellar_xdr::curr::Error::Invalid
| stellar_xdr::curr::Error::Unsupported
| stellar_xdr::curr::Error::LengthExceedsMax
| stellar_xdr::curr::Error::LengthMismatch
| stellar_xdr::curr::Error::NonZeroPadding
| stellar_xdr::curr::Error::Utf8Error(_)
| stellar_xdr::curr::Error::InvalidHex
| stellar_xdr::curr::Error::Io(_)
| stellar_xdr::curr::Error::DepthLimitExceeded => Error::WriteXdrCurr(e),
stellar_xdr::curr::Error::Json(_) => Error::ReadJsonCurr(e),
}
}
}

impl From<stellar_xdr::next::Error> for Error {
fn from(e: stellar_xdr::next::Error) -> Self {
match e {
stellar_xdr::next::Error::Invalid
| stellar_xdr::next::Error::Unsupported
| stellar_xdr::next::Error::LengthExceedsMax
| stellar_xdr::next::Error::LengthMismatch
| stellar_xdr::next::Error::NonZeroPadding
| stellar_xdr::next::Error::Utf8Error(_)
| stellar_xdr::next::Error::InvalidHex
| stellar_xdr::next::Error::Io(_)
| stellar_xdr::next::Error::DepthLimitExceeded => Error::WriteXdrNext(e),
stellar_xdr::next::Error::Json(_) => Error::ReadJsonNext(e),
}
}
}

#[derive(Args, Debug, Clone)]
#[command()]
pub struct Cmd {
/// Files to encode, or stdin if omitted
#[arg()]
files: Vec<PathBuf>,

/// XDR type to encode
#[arg(long)]
r#type: String,

// Input format
#[arg(long, value_enum, default_value_t)]
input: InputFormat,

// Output format to encode to
#[arg(long, value_enum, default_value_t)]
output: OutputFormat,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
pub enum InputFormat {
Json,
}

impl Default for InputFormat {
fn default() -> Self {
Self::Json
}
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
pub enum OutputFormat {
Single,
SingleBase64,
}

impl Default for OutputFormat {
fn default() -> Self {
Self::SingleBase64
}
}

macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
use stellar_xdr::$m::WriteXdr;
let mut files = self.files()?;
let r#type = stellar_xdr::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(
self.r#type.clone(),
&stellar_xdr::$m::TypeVariant::VARIANTS_STR,
)
})?;
for f in &mut files {
match self.input {
InputFormat::Json => {
let t = stellar_xdr::$m::Type::read_json(r#type, f)?;

match self.output {
OutputFormat::Single => stdout().write_all(&t.to_xdr()?)?,
OutputFormat::SingleBase64 => println!("{}", t.to_xdr_base64()?),
}
}
};
}
Ok(())
}
};
}

impl Cmd {
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);

fn files(&self) -> Result<Vec<Box<dyn Read>>, Error> {
if self.files.is_empty() {
Ok(vec![Box::new(stdin())])
} else {
Ok(self
.files
.iter()
.map(File::open)
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.map(|f| -> Box<dyn Read> { Box::new(f) })
.collect())
}
}
}
4 changes: 4 additions & 0 deletions src/bin/stellar-xdr/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod decode;
mod encode;
mod guess;
mod types;
mod version;
Expand Down Expand Up @@ -47,6 +48,8 @@ enum Cmd {
Guess(guess::Cmd),
/// Decode XDR
Decode(decode::Cmd),
/// Encode XDR
Encode(encode::Cmd),
/// Print version information
Version,
}
Expand All @@ -57,6 +60,7 @@ fn run() -> Result<(), Box<dyn Error>> {
Cmd::Types(c) => c.run(&root.channel)?,
Cmd::Guess(c) => c.run(&root.channel)?,
Cmd::Decode(c) => c.run(&root.channel)?,
Cmd::Encode(c) => c.run(&root.channel)?,
Cmd::Version => version::Cmd::run(),
}
Ok(())
Expand Down
Loading

0 comments on commit b96ca71

Please sign in to comment.