Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add schemars::JsonSchema derives to all types #347

Merged
merged 24 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading