bt_common/
debug_command.rs1use std::str::FromStr;
8
9pub trait CommandSet: FromStr + ::core::fmt::Display {
14 fn variants() -> Vec<String>;
16
17 fn arguments(&self) -> &'static str;
20
21 fn flags(&self) -> &'static str;
24
25 fn desc(&self) -> &'static str;
27
28 fn help_simple(&self) -> String {
31 format!("{self} {} {} -- {}", self.flags(), self.arguments(), self.desc())
32 }
33
34 fn help_all() -> String {
36 Self::variants()
37 .into_iter()
38 .filter_map(|s| FromStr::from_str(&s).ok())
39 .map(|s: Self| format!("{}\n", s))
40 .collect()
41 }
42}
43
44#[macro_export]
46macro_rules! gen_commandset {
47 ($name:ident {
48 $($variant:ident = ($val:expr, [$($flag:expr),*], [$($arg:expr),*], $help:expr)),*,
49 }) => {
50 #[derive(PartialEq, Debug)]
52 pub enum $name {
53 $($variant),*
54 }
55
56 impl CommandSet for $name {
57 fn variants() -> Vec<String> {
58 let mut variants = Vec::new();
59 $(variants.push($val.to_string());)*
60 variants
61 }
62
63 fn arguments(&self) -> &'static str {
64 match self {
65 $(
66 $name::$variant => concat!($("<", $arg, "> ",)*)
67 ),*
68 }
69 }
70
71 fn flags(&self) -> &'static str {
72 match self {
73 $(
74 $name::$variant => concat!($("[", $flag, "] ",)*)
75 ),*
76 }
77 }
78
79 fn desc(&self) -> &'static str {
80 match self {
81 $(
82 $name::$variant => $help
83 ),*
84 }
85 }
86 }
87
88 impl ::core::fmt::Display for $name {
89 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
90 match *self {
91 $($name::$variant => write!(f, $val)),* ,
92 }
93 }
94 }
95
96 impl ::std::str::FromStr for $name {
97 type Err = ();
98
99 fn from_str(s: &str) -> Result<$name, ()> {
100 match s {
101 $($val => Ok($name::$variant)),* ,
102 _ => Err(()),
103 }
104 }
105 }
106 }
107}
108
109pub trait CommandRunner {
111 type Set: CommandSet;
112 fn run(
113 &self,
114 cmd: Self::Set,
115 args: Vec<String>,
116 ) -> impl futures::Future<Output = Result<(), impl ::std::error::Error>>;
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn gen_commandset_simple() {
125 gen_commandset! {
126 TestCmd {
127 One = ("one", [], [], "First Command"),
128 WithFlags = ("with-flags", ["-1","-2"], [], "Command with flags"),
129 WithArgs = ("with-args", [], ["arg", "two"], "Command with args"),
130 WithBoth = ("with-both", ["-w"], ["simple"], "Command with both flags and args"),
131 }
132 }
133
134 let cmd: TestCmd = "one".parse().unwrap();
135
136 assert_eq!(cmd, TestCmd::One);
137
138 let cmd2: TestCmd = "with-flags".parse().unwrap();
139
140 assert_eq!(cmd2.arguments(), "");
141 assert_eq!(cmd2.flags(), "[-1] [-2] ");
142 }
143}