rush_sync_server/commands/
registry.rs1use super::command::Command;
6use crate::core::prelude::*;
7use std::collections::HashMap;
8
9pub struct CommandRegistry {
11 commands: Vec<Box<dyn Command>>,
12 name_map: HashMap<String, usize>,
13 initialized: bool,
14}
15
16impl CommandRegistry {
17 pub fn new() -> Self {
19 Self {
20 commands: Vec::new(),
21 name_map: HashMap::new(),
22 initialized: false,
23 }
24 }
25
26 pub fn register<T: Command>(&mut self, command: T) -> &mut Self {
28 let name = command.name().to_lowercase();
29 let index = self.commands.len();
30
31 self.commands.push(Box::new(command));
32 self.name_map.insert(name, index);
33
34 self
36 }
37
38 pub fn register_boxed(&mut self, command: Box<dyn Command>) -> &mut Self {
40 let name = command.name().to_lowercase();
41 let index = self.commands.len();
42
43 self.commands.push(command);
44 self.name_map.insert(name, index);
45
46 log::debug!("Boxed command registered: {}", self.commands[index].name());
47 self
48 }
49
50 pub fn initialize(&mut self) -> &mut Self {
52 if self.initialized {
53 return self;
54 }
55
56 self.name_map.clear();
59 for (new_idx, cmd) in self.commands.iter().enumerate() {
60 self.name_map.insert(cmd.name().to_lowercase(), new_idx);
61 }
62
63 self.initialized = true;
64 self
69 }
70
71 pub fn find_command(&self, input: &str) -> Option<&dyn Command> {
73 let input = input.trim().to_lowercase();
74
75 if let Some(&index) = self.name_map.get(&input) {
77 return self.commands.get(index).map(|cmd| cmd.as_ref());
78 }
79
80 for cmd in &self.commands {
82 if cmd.is_available() && cmd.matches(&input) {
83 return Some(cmd.as_ref());
84 }
85 }
86
87 None
88 }
89
90 pub fn execute_sync(&self, command: &str, args: &[&str]) -> Option<Result<String>> {
92 self.find_command(command).map(|cmd| cmd.execute_sync(args))
93 }
94
95 pub async fn execute_async(&self, command: &str, args: &[&str]) -> Option<Result<String>> {
97 if let Some(cmd) = self.find_command(command) {
98 Some(cmd.execute_async(args).await)
99 } else {
100 None
101 }
102 }
103
104 pub fn list_commands(&self) -> Vec<(&str, &str)> {
106 self.commands
107 .iter()
108 .filter(|cmd| cmd.is_available())
109 .map(|cmd| (cmd.name(), cmd.description()))
110 .collect()
111 }
112
113 pub fn debug_info(&self) -> String {
115 let total = self.commands.len();
116 let available = self
117 .commands
118 .iter()
119 .filter(|cmd| cmd.is_available())
120 .count();
121 let async_support = self
122 .commands
123 .iter()
124 .filter(|cmd| cmd.supports_async())
125 .count();
126
127 format!(
128 "CommandRegistry: {} total, {} available, {} async-capable, initialized: {}",
129 total, available, async_support, self.initialized
130 )
131 }
132
133 pub fn len(&self) -> usize {
135 self.commands.len()
136 }
137
138 pub fn is_empty(&self) -> bool {
140 self.commands.is_empty()
141 }
142}
143
144impl Default for CommandRegistry {
145 fn default() -> Self {
146 Self::new()
147 }
148}