mithril_aggregator/commands/
config_association.rs1#[macro_export]
21macro_rules! extract_all {
22 (@check_type $variant_val:ident, { $type:ident }) => {
23 {let _:$type = $variant_val;}
24 };
25 (@check_type $variant_val:ident, { $module:ident::$type:ident }) => {
26 {let _:$module::$type = $variant_val;}
27 };
28 (@check_type $variant_val:ident, {}) => {
29 let _ = $variant_val;
30 };
31
32 (@extract_config $config_id:ident, { $type:ident }) => {
33 $type::extract_config($config_id)
34 };
35 (@extract_config $config_id:ident, { $module:ident::$type:ident }) => {
36 $module::$type::extract_config($config_id)
37 };
38 (@extract_config $config_id:ident, {}) => {
39 {
40 let _ = $config_id;
41 std::collections::HashMap::new()
42 }
43 };
44
45 ($command_path: ident, $E:path, $($variant:ident = $cmd:tt,)*) => {
46 {
47 use $E as E;
49 let _ = |dummy: E| {
50 match dummy {
51 $(E::$variant(x) => {
52 extract_all!(@check_type x, $cmd);
53 }),*
54 }
55 };
56
57 let mut configs = HashMap::new();
59 $(
60 let config_id = format!(
61 "{} {}",
62 $command_path, stringify!($variant).to_lowercase()
63 );
64 configs.extend(extract_all!(@extract_config config_id, $cmd));
65 )*
66 configs
67 }
68
69 };
70}
71
72#[cfg(test)]
73mod tests {
74 use std::collections::HashMap;
75
76 use mithril_common::assert_equivalent_macro;
77 use mithril_doc::StructDoc;
78
79 #[allow(dead_code)]
80 #[derive(Debug, Clone)]
81 enum PseudoCommand {
82 CommandA(PseudoCommandA),
83 CommandB(pseudo_module::PseudoCommandB),
84 CommandWithoutConfig(PseudoCommandWithoutConfig),
85 CommandConfigUnwanted(PseudoCommandConfigUnwanted),
86 CommandE(EnumCommandE),
87 }
88
89 #[derive(Debug, Clone)]
90 struct PseudoCommandA {}
91 impl PseudoCommandA {
92 pub fn extract_config(command_path: String) -> HashMap<String, StructDoc> {
93 let mut struct_doc = StructDoc::default();
94 struct_doc.add_param("field_command_a", "", None, None, None, true);
95 HashMap::from([(command_path, struct_doc)])
96 }
97 }
98
99 #[derive(Debug, Clone)]
100 struct PseudoCommandWithoutConfig {}
101 impl PseudoCommandWithoutConfig {
102 pub fn extract_config(_command_path: String) -> HashMap<String, StructDoc> {
103 HashMap::new()
104 }
105 }
106
107 #[derive(Debug, Clone)]
108 struct PseudoCommandConfigUnwanted {}
109
110 #[allow(dead_code)]
111 #[derive(Debug, Clone)]
112 enum EnumCommandE {
113 SubCommandE(PseudoSubCommandE),
114 }
115
116 impl EnumCommandE {
117 pub fn extract_config(command_path: String) -> HashMap<String, StructDoc> {
118 extract_all!(
119 command_path,
120 EnumCommandE,
121 SubCommandE = { PseudoSubCommandE },
122 )
123 }
124 }
125
126 #[derive(Debug, Clone)]
127 struct PseudoSubCommandE {}
128 impl PseudoSubCommandE {
129 pub fn extract_config(command_path: String) -> HashMap<String, StructDoc> {
130 let mut struct_doc = StructDoc::default();
131 struct_doc.add_param("field_sub_command_e", "", None, None, None, true);
132 HashMap::from([(command_path, struct_doc)])
133 }
134 }
135
136 mod pseudo_module {
137 use super::*;
138
139 #[derive(Debug, Clone)]
140 pub struct PseudoCommandB {}
141 impl PseudoCommandB {
142 pub fn extract_config(command_path: String) -> HashMap<String, StructDoc> {
143 let mut struct_doc = StructDoc::default();
144 struct_doc.add_param("field_command_b", "", None, None, None, true);
145 HashMap::from([(command_path, struct_doc)])
146 }
147 }
148 }
149
150 #[test]
151 fn test_extract_all_should_construct_hashmap_with_subcommand() {
152 let command_path = "mithril".to_string();
153 let configs = extract_all!(
154 command_path,
155 PseudoCommand,
156 CommandA = { PseudoCommandA },
157 CommandB = { pseudo_module::PseudoCommandB },
158 CommandWithoutConfig = { PseudoCommandWithoutConfig },
159 CommandConfigUnwanted = {},
160 CommandE = { EnumCommandE },
161 );
162
163 let keys: Vec<String> = configs.clone().into_keys().collect();
164 let expected = vec![
165 "mithril commanda".to_string(),
166 "mithril commandb".to_string(),
167 "mithril commande subcommande".to_string(),
168 ];
169
170 assert_equivalent_macro!(expected, keys);
171 }
172
173 #[test]
174 fn test_extract_all_should_associate_struct_doc() {
175 let command_path = "mithril".to_string();
176 let configs = extract_all!(
177 command_path,
178 PseudoCommand,
179 CommandA = { PseudoCommandA },
180 CommandB = { pseudo_module::PseudoCommandB },
181 CommandWithoutConfig = { PseudoCommandWithoutConfig },
182 CommandConfigUnwanted = {},
183 CommandE = { EnumCommandE },
184 );
185 let doc_command_b = configs.get("mithril commandb").unwrap();
186 assert!(doc_command_b.get_field("field_command_b").is_some());
187 assert_eq!(1, doc_command_b.get_ordered_data().len());
188
189 let doc_sub_command_e = configs.get("mithril commande subcommande").unwrap();
190 assert!(doc_sub_command_e.get_field("field_sub_command_e").is_some());
191 assert_eq!(1, doc_sub_command_e.get_ordered_data().len());
192 }
193}