memscope_rs/core/tracker/
config.rs

1//! Configuration and export options for memory tracking.
2//!
3//! This module contains configuration structures and enums used throughout
4//! the memory tracking system, particularly for export operations.
5
6// use crate::export::optimized_json_export::OptimizedExportOptions;
7
8/// Export options for JSON export - user-controllable settings
9#[derive(Debug, Clone)]
10pub struct ExportOptions {
11    /// Include system allocations in full enrichment (default: false)
12    ///
13    /// **⚠️ Performance Impact**: Setting this to `true` can make export 5-10x slower!
14    ///
15    /// - `false` (default): Only user-tracked variables get full enrichment (~2-5 seconds)
16    /// - `true`: ALL allocations including system internals get enrichment (~10-40 seconds)
17    pub include_system_allocations: bool,
18
19    /// Enable verbose logging during export (default: false)
20    pub verbose_logging: bool,
21
22    /// Buffer size for file I/O in bytes (default: 64KB)
23    pub buffer_size: usize,
24
25    /// Enable data compression (default: false)
26    pub compress_output: bool,
27}
28
29impl Default for ExportOptions {
30    fn default() -> Self {
31        Self {
32            include_system_allocations: false, // Fast mode by default
33            verbose_logging: false,
34            buffer_size: 64 * 1024, // 64KB
35            compress_output: false,
36        }
37    }
38}
39
40impl ExportOptions {
41    /// Create new export options with default settings (fast mode)
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    /// Enable system allocation enrichment (⚠️ SLOW - 5-10x slower!)
47    ///
48    /// # Warning
49    /// This will significantly slow down the export process and generate much larger files.
50    /// Only use for deep debugging or system analysis.
51    ///
52    /// # Example
53    /// ```text
54    /// let options = ExportOptions::new().include_system_allocations(true);
55    /// tracker.export_to_json_with_options("debug_output", options)?;
56    /// ```
57    pub fn include_system_allocations(mut self, include: bool) -> Self {
58        self.include_system_allocations = include;
59        self
60    }
61
62    /// Enable verbose logging during export
63    pub fn verbose_logging(mut self, verbose: bool) -> Self {
64        self.verbose_logging = verbose;
65        self
66    }
67
68    /// Set custom buffer size for file I/O
69    pub fn buffer_size(mut self, size: usize) -> Self {
70        self.buffer_size = size;
71        self
72    }
73
74    /// Enable output compression (experimental)
75    pub fn compress_output(mut self, compress: bool) -> Self {
76        self.compress_output = compress;
77        self
78    }
79}
80
81/// Internal export mode derived from options
82#[derive(Debug, Clone, Copy)]
83pub enum ExportMode {
84    /// Fast mode: Only enrich user-tracked variables
85    UserFocused,
86    /// Complete mode: Enrich all allocations including system data
87    Complete,
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_export_options_default() {
96        let options = ExportOptions::default();
97
98        assert!(!options.include_system_allocations);
99        assert!(!options.verbose_logging);
100        assert_eq!(options.buffer_size, 64 * 1024);
101        assert!(!options.compress_output);
102    }
103
104    #[test]
105    fn test_export_options_new() {
106        let options = ExportOptions::new();
107
108        // new() should be equivalent to default()
109        assert!(!options.include_system_allocations);
110        assert!(!options.verbose_logging);
111        assert_eq!(options.buffer_size, 64 * 1024);
112        assert!(!options.compress_output);
113    }
114
115    #[test]
116    fn test_export_options_builder_pattern() {
117        let options = ExportOptions::new()
118            .include_system_allocations(true)
119            .verbose_logging(true)
120            .buffer_size(128 * 1024)
121            .compress_output(true);
122
123        assert!(options.include_system_allocations);
124        assert!(options.verbose_logging);
125        assert_eq!(options.buffer_size, 128 * 1024);
126        assert!(options.compress_output);
127    }
128
129    #[test]
130    fn test_export_options_individual_setters() {
131        let mut options = ExportOptions::new();
132
133        // Test include_system_allocations
134        options = options.include_system_allocations(true);
135        assert!(options.include_system_allocations);
136
137        options = options.include_system_allocations(false);
138        assert!(!options.include_system_allocations);
139
140        // Test verbose_logging
141        options = options.verbose_logging(true);
142        assert!(options.verbose_logging);
143
144        options = options.verbose_logging(false);
145        assert!(!options.verbose_logging);
146
147        // Test buffer_size
148        options = options.buffer_size(1024);
149        assert_eq!(options.buffer_size, 1024);
150
151        options = options.buffer_size(256 * 1024);
152        assert_eq!(options.buffer_size, 256 * 1024);
153
154        // Test compress_output
155        options = options.compress_output(true);
156        assert!(options.compress_output);
157
158        options = options.compress_output(false);
159        assert!(!options.compress_output);
160    }
161
162    #[test]
163    fn test_export_options_chaining() {
164        // Test that method chaining works correctly
165        let options1 = ExportOptions::new()
166            .include_system_allocations(true)
167            .verbose_logging(true);
168
169        let options2 = options1
170            .clone()
171            .buffer_size(32 * 1024)
172            .compress_output(true);
173
174        // Original options1 should be unchanged (methods consume self)
175        assert!(options1.include_system_allocations);
176        assert!(options1.verbose_logging);
177        assert_eq!(options1.buffer_size, 64 * 1024); // Still default
178        assert!(!options1.compress_output); // Still default
179
180        // options2 should have all changes
181        assert!(options2.include_system_allocations);
182        assert!(options2.verbose_logging);
183        assert_eq!(options2.buffer_size, 32 * 1024);
184        assert!(options2.compress_output);
185    }
186
187    #[test]
188    fn test_export_options_clone() {
189        let original = ExportOptions::new()
190            .include_system_allocations(true)
191            .verbose_logging(true)
192            .buffer_size(128 * 1024)
193            .compress_output(true);
194
195        let cloned = original.clone();
196
197        assert_eq!(
198            original.include_system_allocations,
199            cloned.include_system_allocations
200        );
201        assert_eq!(original.verbose_logging, cloned.verbose_logging);
202        assert_eq!(original.buffer_size, cloned.buffer_size);
203        assert_eq!(original.compress_output, cloned.compress_output);
204    }
205
206    #[test]
207    fn test_export_options_debug() {
208        let options = ExportOptions::new()
209            .include_system_allocations(true)
210            .verbose_logging(false)
211            .buffer_size(32 * 1024)
212            .compress_output(true);
213
214        let debug_str = format!("{options:?}");
215
216        // Should contain all field values
217        assert!(debug_str.contains("include_system_allocations: true"));
218        assert!(debug_str.contains("verbose_logging: false"));
219        assert!(debug_str.contains("buffer_size: 32768"));
220        assert!(debug_str.contains("compress_output: true"));
221    }
222
223    #[test]
224    fn test_export_mode_variants() {
225        // Test that ExportMode variants exist and can be created
226        let user_focused = ExportMode::UserFocused;
227        let complete = ExportMode::Complete;
228
229        // Test Debug trait
230        let debug_user = format!("{user_focused:?}");
231        let debug_complete = format!("{complete:?}");
232
233        assert_eq!(debug_user, "UserFocused");
234        assert_eq!(debug_complete, "Complete");
235    }
236
237    #[test]
238    fn test_export_mode_clone_copy() {
239        let original = ExportMode::UserFocused;
240        let cloned = original; // ExportMode implements Copy, so no clone needed
241        let copied = original;
242
243        // All should be equal (Copy trait)
244        assert!(matches!(original, ExportMode::UserFocused));
245        assert!(matches!(cloned, ExportMode::UserFocused));
246        assert!(matches!(copied, ExportMode::UserFocused));
247
248        let complete_original = ExportMode::Complete;
249        let complete_copied = complete_original;
250
251        assert!(matches!(complete_original, ExportMode::Complete));
252        assert!(matches!(complete_copied, ExportMode::Complete));
253    }
254
255    #[test]
256    fn test_buffer_size_edge_cases() {
257        // Test various buffer sizes
258        let small_buffer = ExportOptions::new().buffer_size(1);
259        assert_eq!(small_buffer.buffer_size, 1);
260
261        let large_buffer = ExportOptions::new().buffer_size(1024 * 1024 * 10); // 10MB
262        assert_eq!(large_buffer.buffer_size, 1024 * 1024 * 10);
263
264        let zero_buffer = ExportOptions::new().buffer_size(0);
265        assert_eq!(zero_buffer.buffer_size, 0);
266    }
267
268    #[test]
269    fn test_export_options_realistic_configurations() {
270        // Test realistic configuration scenarios
271
272        // Fast development mode
273        let dev_config = ExportOptions::new()
274            .include_system_allocations(false)
275            .verbose_logging(false)
276            .buffer_size(64 * 1024)
277            .compress_output(false);
278
279        assert!(!dev_config.include_system_allocations);
280        assert!(!dev_config.verbose_logging);
281        assert_eq!(dev_config.buffer_size, 64 * 1024);
282        assert!(!dev_config.compress_output);
283
284        // Debug mode with full details
285        let debug_config = ExportOptions::new()
286            .include_system_allocations(true)
287            .verbose_logging(true)
288            .buffer_size(128 * 1024)
289            .compress_output(false);
290
291        assert!(debug_config.include_system_allocations);
292        assert!(debug_config.verbose_logging);
293        assert_eq!(debug_config.buffer_size, 128 * 1024);
294        assert!(!debug_config.compress_output);
295
296        // Production mode with compression
297        let prod_config = ExportOptions::new()
298            .include_system_allocations(false)
299            .verbose_logging(false)
300            .buffer_size(256 * 1024)
301            .compress_output(true);
302
303        assert!(!prod_config.include_system_allocations);
304        assert!(!prod_config.verbose_logging);
305        assert_eq!(prod_config.buffer_size, 256 * 1024);
306        assert!(prod_config.compress_output);
307    }
308}