kal/
command_spec.rs

1use crate::{CommaSeparated, SpaceSeparated};
2
3/// The specification of coomand
4#[derive(Debug, PartialEq)]
5pub struct CommandSpec {
6    /// The name of command
7    pub name: &'static str,
8
9    /// The description of command
10    pub description: &'static str,
11
12    /// The options command can take
13    pub options: Vec<CommandOption>,
14
15    /// The subcommands command have
16    pub subcommands: Vec<CommandSpec>,
17}
18
19/// The option command cane take
20#[derive(Debug, PartialEq)]
21pub struct CommandOption {
22    /// The name of option when it is treated as named argument
23    pub name: &'static str,
24
25    /// The position of option when it is treated as positional argument
26    pub position: usize,
27
28    /// The description of option
29    pub description: &'static str,
30
31    /// The kind of value option can take
32    pub value: CommandOptionValueKind,
33}
34
35/// The kind of value option can take
36#[derive(Clone, Debug, PartialEq)]
37pub enum CommandOptionValueKind {
38    /// A kind of value that can appear or not
39    Optional(Box<CommandOptionValueKind>),
40
41    /// A kind of value that can appear or not
42    Multiple(Box<CommandOptionValueKind>),
43
44    /// String value
45    String,
46
47    /// Integer value
48    Integer,
49
50    /// Double precision floating point value
51    Double,
52}
53
54impl CommandOptionValueKind {
55    /// Whether the option value can be optional
56    pub fn is_optional(&self) -> bool {
57        matches!(self, CommandOptionValueKind::Optional(_))
58    }
59
60    /// Make the option value kind as primitive as possible
61    pub fn as_primitive(&self) -> CommandOptionValueKind {
62        match self {
63            CommandOptionValueKind::Optional(t) | CommandOptionValueKind::Multiple(t) => {
64                t.as_primitive()
65            }
66            _ => self.clone(),
67        }
68    }
69}
70
71/// Associate Rust type with [`CommandOptionValueKind`] and provide Rust side default value.
72pub trait CommandOptionValueTy: Sized {
73    /// Associated value kind
74    fn spec_kind() -> CommandOptionValueKind;
75
76    /// The default value for Rust side
77    fn default() -> Option<Self> {
78        None
79    }
80}
81
82impl<T: CommandOptionValueTy> CommandOptionValueTy for Option<T> {
83    fn spec_kind() -> CommandOptionValueKind {
84        CommandOptionValueKind::Optional(Box::new(T::spec_kind()))
85    }
86
87    fn default() -> Option<Self> {
88        Some(None)
89    }
90}
91
92impl CommandOptionValueTy for String {
93    fn spec_kind() -> CommandOptionValueKind {
94        CommandOptionValueKind::String
95    }
96}
97
98impl CommandOptionValueTy for i64 {
99    fn spec_kind() -> CommandOptionValueKind {
100        CommandOptionValueKind::Integer
101    }
102}
103
104impl CommandOptionValueTy for f64 {
105    fn spec_kind() -> CommandOptionValueKind {
106        CommandOptionValueKind::Double
107    }
108}
109
110impl<T: CommandOptionValueTy> CommandOptionValueTy for SpaceSeparated<T> {
111    fn spec_kind() -> CommandOptionValueKind {
112        CommandOptionValueKind::Multiple(Box::new(T::spec_kind()))
113    }
114}
115
116impl<T: CommandOptionValueTy> CommandOptionValueTy for CommaSeparated<T> {
117    fn spec_kind() -> CommandOptionValueKind {
118        CommandOptionValueKind::Multiple(Box::new(T::spec_kind()))
119    }
120}