rush_sync_server/commands/
registry.rs1use super::command::Command;
2use crate::core::prelude::*;
3use std::collections::HashMap;
4
5pub struct CommandRegistry {
6 commands: Vec<Box<dyn Command>>,
7 name_map: HashMap<String, usize>,
8 initialized: bool,
9}
10
11impl CommandRegistry {
12 pub fn new() -> Self {
13 Self {
14 commands: Vec::new(),
15 name_map: HashMap::new(),
16 initialized: false,
17 }
18 }
19
20 pub fn register<T: Command>(&mut self, command: T) -> &mut Self {
21 let name = command.name().to_lowercase();
22 let index = self.commands.len();
23
24 self.commands.push(Box::new(command));
25 self.name_map.insert(name, index);
26 self
27 }
28
29 pub fn register_boxed(&mut self, command: Box<dyn Command>) -> &mut Self {
30 let name = command.name().to_lowercase();
31 let index = self.commands.len();
32
33 self.commands.push(command);
34 self.name_map.insert(name, index);
35 self
36 }
37
38 pub fn initialize(&mut self) -> &mut Self {
39 if self.initialized {
40 return self;
41 }
42
43 self.name_map.clear();
44 for (new_idx, cmd) in self.commands.iter().enumerate() {
45 self.name_map.insert(cmd.name().to_lowercase(), new_idx);
46 }
47
48 self.initialized = true;
49 self
50 }
51
52 pub fn find_command(&self, input: &str) -> Option<&dyn Command> {
53 let input = input.trim().to_lowercase();
54
55 if let Some(&index) = self.name_map.get(&input) {
57 return self.commands.get(index).map(|cmd| cmd.as_ref());
58 }
59
60 for cmd in &self.commands {
62 if cmd.is_available() && cmd.matches(&input) {
63 return Some(cmd.as_ref());
64 }
65 }
66
67 None
68 }
69
70 pub fn execute_sync(&self, command: &str, args: &[&str]) -> Option<Result<String>> {
72 self.find_command(command).map(|cmd| cmd.execute_sync(args))
73 }
74
75 pub async fn execute_async(&self, command: &str, args: &[&str]) -> Option<Result<String>> {
77 if let Some(cmd) = self.find_command(command) {
78 Some(cmd.execute_async(args).await)
79 } else {
80 None
81 }
82 }
83
84 pub fn list_commands(&self) -> Vec<(&str, &str)> {
85 self.commands
86 .iter()
87 .filter(|cmd| cmd.is_available())
88 .map(|cmd| (cmd.name(), cmd.description()))
89 .collect()
90 }
91
92 pub fn debug_info(&self) -> String {
93 format!(
94 "CommandRegistry: {} commands, initialized: {}",
95 self.commands.len(),
96 self.initialized
97 )
98 }
99
100 pub fn len(&self) -> usize {
101 self.commands.len()
102 }
103 pub fn is_empty(&self) -> bool {
104 self.commands.is_empty()
105 }
106}
107
108impl Default for CommandRegistry {
109 fn default() -> Self {
110 Self::new()
111 }
112}