sql_cli/debug/
debug_registry.rs1use super::debug_trace::{DebugSection, DebugTrace};
2use std::sync::{Arc, RwLock};
3
4pub struct DebugRegistry {
6 providers: Arc<RwLock<Vec<Arc<dyn DebugTrace>>>>,
7}
8
9impl DebugRegistry {
10 pub fn new() -> Self {
12 Self {
13 providers: Arc::new(RwLock::new(Vec::new())),
14 }
15 }
16
17 pub fn register(&self, provider: Arc<dyn DebugTrace>) {
19 if let Ok(mut providers) = self.providers.write() {
20 let name = provider.name();
22 providers.retain(|p| p.name() != name);
23 providers.push(provider);
24 }
25 }
26
27 pub fn unregister(&self, name: &str) {
29 if let Ok(mut providers) = self.providers.write() {
30 providers.retain(|p| p.name() != name);
31 }
32 }
33
34 pub fn clear(&self) {
36 if let Ok(mut providers) = self.providers.write() {
37 providers.clear();
38 }
39 }
40
41 pub fn collect_debug_sections(&self) -> Vec<DebugSection> {
43 let mut all_sections = Vec::new();
44
45 if let Ok(providers) = self.providers.read() {
46 for provider in providers.iter() {
47 if provider.is_active() {
48 all_sections.extend(provider.debug_sections());
49 }
50 }
51 }
52
53 all_sections.sort_by_key(|s| s.priority);
55 all_sections
56 }
57
58 pub fn generate_debug_report(&self) -> String {
60 let sections = self.collect_debug_sections();
61 let mut report = String::new();
62
63 for section in sections {
64 report.push_str(§ion.content);
65 }
66
67 report
68 }
69
70 pub fn list_providers(&self) -> Vec<String> {
72 if let Ok(providers) = self.providers.read() {
73 providers.iter().map(|p| p.name().to_string()).collect()
74 } else {
75 Vec::new()
76 }
77 }
78
79 pub fn collect_summaries(&self) -> Vec<(String, String)> {
81 let mut summaries = Vec::new();
82
83 if let Ok(providers) = self.providers.read() {
84 for provider in providers.iter() {
85 if provider.is_active() {
86 if let Some(summary) = provider.debug_summary() {
87 summaries.push((provider.name().to_string(), summary));
88 }
89 }
90 }
91 }
92
93 summaries
94 }
95
96 pub fn has_provider(&self, name: &str) -> bool {
98 if let Ok(providers) = self.providers.read() {
99 providers.iter().any(|p| p.name() == name)
100 } else {
101 false
102 }
103 }
104
105 pub fn provider_count(&self) -> usize {
107 if let Ok(providers) = self.providers.read() {
108 providers.len()
109 } else {
110 0
111 }
112 }
113}
114
115impl Default for DebugRegistry {
116 fn default() -> Self {
117 Self::new()
118 }
119}
120
121impl Clone for DebugRegistry {
122 fn clone(&self) -> Self {
123 Self {
124 providers: Arc::clone(&self.providers),
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 struct TestProvider {
134 name: String,
135 active: bool,
136 }
137
138 impl DebugTrace for TestProvider {
139 fn name(&self) -> &str {
140 &self.name
141 }
142
143 fn debug_sections(&self) -> Vec<DebugSection> {
144 vec![DebugSection::new(
145 format!("{} Section", self.name),
146 format!("Debug info from {}", self.name),
147 100,
148 )]
149 }
150
151 fn is_active(&self) -> bool {
152 self.active
153 }
154 }
155
156 #[test]
157 fn test_registry_basic() {
158 let registry = DebugRegistry::new();
159
160 let provider1 = Arc::new(TestProvider {
161 name: "Provider1".to_string(),
162 active: true,
163 });
164
165 registry.register(provider1);
166 assert_eq!(registry.provider_count(), 1);
167 assert!(registry.has_provider("Provider1"));
168
169 registry.unregister("Provider1");
170 assert_eq!(registry.provider_count(), 0);
171 }
172
173 #[test]
174 fn test_collect_sections() {
175 let registry = DebugRegistry::new();
176
177 let provider1 = Arc::new(TestProvider {
178 name: "Provider1".to_string(),
179 active: true,
180 });
181
182 let provider2 = Arc::new(TestProvider {
183 name: "Provider2".to_string(),
184 active: false, });
186
187 registry.register(provider1);
188 registry.register(provider2);
189
190 let sections = registry.collect_debug_sections();
191 assert_eq!(sections.len(), 1); assert!(sections[0].title.contains("Provider1"));
193 }
194}