Skip to content

Commit

Permalink
Add schemars::JsonSchema derives to all types (#347)
Browse files Browse the repository at this point in the history
* Add schemars::JsonSchema derives to all types

* add test

* remove unused dev dep

* silence clippy warning

* regen with new feature and manual impls from willem

* upd

* fix

* upd

* fix overflow

* add first version of command

* ping to draft7

* upd

* group new features

* custom types

* upd

* upd ver

* update xdr

* upd

* upd

* fix claimable balance id
  • Loading branch information
leighmcculloch authored May 16, 2024
1 parent 9209690 commit 89a8bcd
Show file tree
Hide file tree
Showing 15 changed files with 2,729 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
merge_group:

env:
CARGO_HACK_ARGS: --feature-powerset --exclude-features default --group-features base64,serde,arbitrary,hex
CARGO_HACK_ARGS: --feature-powerset --exclude-features default --group-features base64,serde,serde_json,schemars,arbitrary,hex

jobs:

Expand Down
42 changes: 42 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ arbitrary = {version = "1.1.3", features = ["derive"], optional = true}
clap = { version = "4.2.4", default-features = false, features = ["std", "derive", "usage", "help"], optional = true }
serde_json = { version = "1.0.89", optional = true }
thiserror = { version = "1.0.37", optional = true }
schemars = { version = "0.8.16", optional = true }

[dev_dependencies]
serde_json = "1.0.89"
Expand All @@ -44,11 +45,12 @@ next = []
base64 = ["std", "dep:base64"]
serde = ["alloc", "dep:serde", "dep:serde_with", "hex/serde"]
serde_json = ["std", "serde", "dep:serde_json"]
schemars = ["alloc", "serde", "serde_json", "dep:schemars"]
arbitrary = ["std", "dep:arbitrary"]
hex = []

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

[package.metadata.docs.rs]
all-features = true
Expand Down
31 changes: 23 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features b

CARGO_DOC_ARGS?=--open

XDRGEN_VERSION=e2cac557162d99b12ae73b846cf3d5bfe16636de
XDRGEN_VERSION=ac1653599b97b298e72c0186b5685bffa120b6aa
# XDRGEN_LOCAL=1
XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId
XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId
XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_CURR=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId
XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_NEXT=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress,AssetCode,AssetCode4,AssetCode12,ClaimableBalanceId

all: build test

Expand All @@ -22,7 +25,7 @@ doc:
RUSTDOCFLAGS="--cfg docs" cargo +nightly doc --package stellar-xdr --all-features $(CARGO_DOC_ARGS)

install:
cargo install --path . --force --features cli
cargo install --locked --path . --force --features cli

readme:
cargo readme > README.md
Expand All @@ -34,16 +37,22 @@ generate: src/curr/generated.rs xdr/curr-version src/next/generated.rs xdr/next-

src/curr/generated.rs: $(sort $(wildcard xdr/curr/*.x))
> $@
ifeq ($(LOCAL_XDRGEN),)
ifeq ($(XDRGEN_LOCAL),)
docker run -i --rm -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\
gem install specific_install -v 0.3.8 && \
gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_VERSION) && \
xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) $^ \
xdrgen --language rust --namespace generated --output src/curr \
--rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) \
--rust-types-custom-jsonschema-impl '$(XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_CURR)' \
$^ \
'
else
docker run -i --rm -v $$PWD/../xdrgen:/xdrgen -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\
pushd /xdrgen && bundle install --deployment && rake install && popd && \
xdrgen --language rust --namespace generated --output src/curr --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) $^ \
xdrgen --language rust --namespace generated --output src/curr \
--rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_CURR) \
--rust-types-custom-jsonschema-impl '$(XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_CURR)' \
$^ \
'
endif
rustfmt $@
Expand All @@ -53,16 +62,22 @@ xdr/curr-version: $(wildcard .git/modules/xdr/curr/**/*) $(wildcard xdr/curr/*.x

src/next/generated.rs: $(sort $(wildcard xdr/next/*.x))
> $@
ifeq ($(LOCAL_XDRGEN),)
ifeq ($(XDRGEN_LOCAL),)
docker run -i --rm -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\
gem install specific_install -v 0.3.8 && \
gem specific_install https://github.com/stellar/xdrgen.git -b $(XDRGEN_VERSION) && \
xdrgen --language rust --namespace generated --output src/next --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) $^ \
xdrgen --language rust --namespace generated --output src/next \
--rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) \
--rust-types-custom-jsonschema-impl '$(XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_NEXT)' \
$^ \
'
else
docker run -i --rm -v $$PWD/../xdrgen:/xdrgen -v $$PWD:/wd -w /wd docker.io/library/ruby:latest /bin/bash -c '\
pushd /xdrgen && bundle install --deployment && rake install && popd && \
xdrgen --language rust --namespace generated --output src/next --rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) $^ \
xdrgen --language rust --namespace generated --output src/next \
--rust-types-custom-str-impl $(XDRGEN_TYPES_CUSTOM_STR_IMPL_NEXT) \
--rust-types-custom-jsonschema-impl '$(XDRGEN_TYPES_CUSTOM_JSONSCHEMA_IMPL_NEXT)' \
$^ \
'
endif
rustfmt $@
Expand Down
5 changes: 4 additions & 1 deletion src/bin/stellar-xdr/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ fn main() {
if let Err(e) = cli::run(env::args_os()) {
match e {
cli::Error::Clap(e) => e.exit(),
cli::Error::Guess(_) | cli::Error::Decode(_) | cli::Error::Encode(_) => {
cli::Error::Types(_)
| cli::Error::Guess(_)
| cli::Error::Decode(_)
| cli::Error::Encode(_) => {
Error::raw(clap::error::ErrorKind::ValueValidation, e).exit()
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl Root {
/// If the root command is configured with state that is invalid.
pub fn run(&self) -> Result<(), Error> {
match &self.cmd {
Cmd::Types(c) => c.run(&self.channel),
Cmd::Types(c) => c.run(&self.channel)?,
Cmd::Guess(c) => c.run(&self.channel)?,
Cmd::Decode(c) => c.run(&self.channel)?,
Cmd::Encode(c) => c.run(&self.channel)?,
Expand Down Expand Up @@ -77,6 +77,8 @@ pub enum Cmd {
pub enum Error {
#[error("{0}")]
Clap(#[from] clap::Error),
#[error("{0}")]
Types(#[from] types::Error),
#[error("error decoding XDR: {0}")]
Guess(#[from] guess::Error),
#[error("error reading file: {0}")]
Expand Down
18 changes: 16 additions & 2 deletions src/cli/types.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
pub mod list;
mod schema;

use clap::{Args, Subcommand};

use crate::cli::Channel;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("{0}")]
SchemaError(#[from] schema::Error),
}

#[derive(Args, Debug, Clone)]
#[command()]
pub struct Cmd {
Expand All @@ -14,17 +21,24 @@ pub struct Cmd {
#[derive(Subcommand, Clone, Debug)]
enum Sub {
List(list::Cmd),
Schema(schema::Cmd),
}

impl Cmd {
/// Run the CLIs types command.
///
/// ## Errors
///
/// If the sub-command panics.
///
/// ## Panics
///
/// If the lists sub-command panics.
pub fn run(&self, channel: &Channel) {
/// If the sub-command panics.
pub fn run(&self, channel: &Channel) -> Result<(), Error> {
match &self.sub {
Sub::List(c) => c.run(channel),
Sub::Schema(c) => c.run(channel)?,
}
Ok(())
}
}
68 changes: 68 additions & 0 deletions src/cli/types/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use clap::{Args, ValueEnum};
use schemars::gen::SchemaSettings;

use crate::cli::Channel;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("unknown type {0}, choose one of {1:?}")]
UnknownType(String, &'static [&'static str]),
#[error("error generating JSON: {0}")]
GenerateJson(#[from] serde_json::Error),
}

#[derive(Args, Debug, Clone)]
#[command()]
pub struct Cmd {
/// XDR type to decode
#[arg(long)]
r#type: String,

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

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

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

macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
use std::str::FromStr;
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 settings = match self.output {
OutputFormat::JsonSchemaDraft7 => SchemaSettings::draft07(),
OutputFormat::JsonSchemaDraft201909 => SchemaSettings::draft2019_09(),
};
let generator = settings.into_generator();
let schema = r#type.json_schema(generator);
println!("{}", serde_json::to_string_pretty(&schema)?);
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);
}
Loading

0 comments on commit 89a8bcd

Please sign in to comment.