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