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    #[must_use]
12    pub fn new() -> Self {
13        Self {
14            providers: Arc::new(RwLock::new(Vec::new())),
15        }
16    }
17
18    /// Register a debug provider
19    pub fn register(&self, provider: Arc<dyn DebugTrace>) {
20        if let Ok(mut providers) = self.providers.write() {
21            // Check if provider with same name already exists
22            let name = provider.name();
23            providers.retain(|p| p.name() != name);
24            providers.push(provider);
25        }
26    }
27
28    /// Unregister a debug provider by name
29    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    /// Clear all providers
36    pub fn clear(&self) {
37        if let Ok(mut providers) = self.providers.write() {
38            providers.clear();
39        }
40    }
41
42    /// Get all debug sections from active providers
43    #[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        // Sort by priority
56        all_sections.sort_by_key(|s| s.priority);
57        all_sections
58    }
59
60    /// Generate a complete debug report
61    #[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(&section.content);
68        }
69
70        report
71    }
72
73    /// Get a list of registered provider names
74    #[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    /// Get debug summaries from all active providers
84    #[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    /// Check if a provider is registered
102    #[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    /// Get the count of registered providers
112    #[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, // Not active
192        });
193
194        registry.register(provider1);
195        registry.register(provider2);
196
197        let sections = registry.collect_debug_sections();
198        assert_eq!(sections.len(), 1); // Only active provider's section
199        assert!(sections[0].title.contains("Provider1"));
200    }
201}