Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
heartwood crates radicle-schemars src main.rs
use std::io;
use std::net;
use std::sync::LazyLock;

use schemars::{generate::*, *};

const SCHEMA_COMMAND: &str = "radicle::node::Command";
const SCHEMA_COMMAND_RESULT: &str = "radicle::node::CommandResult";
const SCHEMA_PROFILE_CONFIG: &str = "radicle::profile::Config";

const SCHEMAS: &[&str] = &[SCHEMA_COMMAND, SCHEMA_COMMAND_RESULT, SCHEMA_PROFILE_CONFIG];

pub static ERROR_MSG: LazyLock<String> = LazyLock::new(|| {
    let schemas = SCHEMAS.to_vec().join("\", \"");
    format!("Expected exactly one of the following schema names: [\"{schemas}\"].")
});

enum Schema {
    Command,
    CommandResult,
    ProfileConfig,
}

impl std::str::FromStr for Schema {
    type Err = io::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            SCHEMA_COMMAND => Ok(Self::Command),
            SCHEMA_COMMAND_RESULT => Ok(Self::CommandResult),
            SCHEMA_PROFILE_CONFIG => Ok(Self::ProfileConfig),
            schema => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("{schema}: {}", *ERROR_MSG),
            )),
        }
    }
}

impl Schema {
    fn from_args(mut args: std::env::Args) -> io::Result<Self> {
        let name = args.nth(1).ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("No schema given. {}", *ERROR_MSG),
            )
        })?;
        name.parse()
    }
}

fn main() {
    if let Err(e) = print_schema() {
        eprintln!("{e}");
        std::process::exit(1);
    }
}

fn print_schema() -> io::Result<()> {
    let args = std::env::args();

    let name = Schema::from_args(args)?;

    let schema = match name {
        Schema::Command => {
            let settings = SchemaSettings::default().for_serialize();
            let generator = settings.into_generator();

            generator.into_root_schema_for::<radicle::node::Command>()
        }
        Schema::CommandResult => {
            #[derive(JsonSchema)]
            #[allow(dead_code)]
            struct ListenAddrs(Vec<net::SocketAddr>);

            #[derive(JsonSchema)]
            #[allow(dead_code)]
            struct Error {
                error: String,
            }

            #[derive(JsonSchema)]
            #[schemars(untagged)]
            #[allow(dead_code)]
            enum CommandResult {
                Nid(radicle::node::NodeId),
                Config(Box<radicle::node::Config>),
                ListenAddrs(ListenAddrs),
                ConnectResult(radicle::node::ConnectResult),
                Success(radicle::node::Success),
                Seeds(radicle::node::Seeds),
                FetchResult(radicle::node::FetchResult),
                RefsAt(radicle::storage::refs::RefsAt),
                Sessions(Vec<radicle::node::Session>),
                Session(Option<radicle::node::Session>),
                Error(Error),
            }
            schema_for!(CommandResult)
        }
        Schema::ProfileConfig => schemars::schema_for!(radicle::profile::Config),
    };

    serde_json::to_writer_pretty(std::io::stdout(), &schema)?;
    Ok(())
}