sql_cli/debug/
debug_registry.rs

1use super::debug_trace::{DebugSection, DebugTrace};
2use std::sync::{Arc, RwLock};
3
4/// Registry for managing debug trace providers
5pub struct DebugRegistry {
6    providers: Arc<RwLock<Vec<Arc<dyn DebugTrace>>>>,
7}
8
9impl DebugRegistry {
10    /// Create a new debug registry
11    pub fn new() -> Self {
12        Self {
13            providers: Arc::new(RwLock::new(Vec::new())),
14        }
15    }
16
17    /// Register a debug provider
18    pub fn register(&self, provider: Arc<dyn DebugTrace>) {
19        if let Ok(mut providers) = self.providers.write() {
20            // Check if provider with same name already exists
21            let name = provider.name();
22            providers.retain(|p| p.name() != name);
23            providers.push(provider);
24        }
25    }
26
27    /// Unregister a debug provider by name
28    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    /// Clear all providers
35    pub fn clear(&self) {
36        if let Ok(mut providers) = self.providers.write() {
37            providers.clear();
38        }
39    }
40
41    /// Get all debug sections from active providers
42    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        // Sort by priority
54        all_sections.sort_by_key(|s| s.priority);
55        all_sections
56    }
57
58    /// Generate a complete debug report
59    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(&section.content);
65        }
66
67        report
68    }
69
70    /// Get a list of registered provider names
71    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    /// Get debug summaries from all active providers
80    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    /// Check if a provider is registered
97    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    /// Get the count of registered providers
106    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, // Not active
185        });
186
187        registry.register(provider1);
188        registry.register(provider2);
189
190        let sections = registry.collect_debug_sections();
191        assert_eq!(sections.len(), 1); // Only active provider's section
192        assert!(sections[0].title.contains("Provider1"));
193    }
194}