stellar_xdr/cli/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
pub mod compare;
pub mod decode;
pub mod encode;
pub mod guess;
mod skip_whitespace;
pub mod types;
mod version;

use clap::{Parser, Subcommand, ValueEnum};
use std::{ffi::OsString, fmt::Debug};

#[derive(Parser, Debug, Clone)]
#[command(
    author,
    version,
    about,
    long_about = None,
    disable_help_subcommand = true,
    disable_version_flag = true,
    disable_colored_help = true,
    infer_subcommands = true,
)]
pub struct Root {
    /// Channel of XDR to operate on
    #[arg(value_enum, default_value_t)]
    channel: Channel,
    #[command(subcommand)]
    cmd: Cmd,
}

impl Root {
    /// Run the CLIs root command.
    ///
    /// ## Errors
    ///
    /// 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::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(())
    }
}

#[derive(ValueEnum, Debug, Clone)]
pub enum Channel {
    #[value(name = "+curr")]
    Curr,
    #[value(name = "+next")]
    Next,
}

impl Default for Channel {
    fn default() -> Self {
        Self::Curr
    }
}

#[derive(Subcommand, Debug, Clone)]
pub enum Cmd {
    /// View information about types
    Types(types::Cmd),
    /// Guess the XDR type
    Guess(guess::Cmd),
    /// Decode XDR
    Decode(decode::Cmd),
    /// Encode XDR
    Encode(encode::Cmd),
    Compare(compare::Cmd),
    /// Print version information
    Version,
}

#[derive(thiserror::Error, Debug)]
#[allow(clippy::enum_variant_names)]
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}")]
    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.
///
/// ## Errors
///
/// If the input cannot be parsed.
pub fn run<I, T>(args: I) -> Result<(), Error>
where
    I: IntoIterator<Item = T>,
    T: Into<OsString> + Clone,
{
    let root = Root::try_parse_from(args)?;
    root.run()
}