pjson_rs/
config.rs

1//! Global configuration for PJS Core library
2//!
3//! This module provides centralized configuration for all components,
4//! replacing hardcoded constants with configurable values.
5
6pub mod security;
7
8use crate::compression::CompressionConfig;
9pub use security::SecurityConfig;
10
11/// Global configuration for PJS library components
12#[derive(Debug, Clone, Default)]
13pub struct PjsConfig {
14    /// Security configuration and limits
15    pub security: SecurityConfig,
16    /// Configuration for compression algorithms
17    pub compression: CompressionConfig,
18    /// Configuration for parsers
19    pub parser: ParserConfig,
20    /// Configuration for streaming
21    pub streaming: StreamingConfig,
22    /// Configuration for SIMD operations
23    pub simd: SimdConfig,
24}
25
26/// Configuration for JSON parsers
27#[derive(Debug, Clone)]
28pub struct ParserConfig {
29    /// Maximum input size in MB
30    pub max_input_size_mb: usize,
31    /// Buffer initial capacity in bytes
32    pub buffer_initial_capacity: usize,
33    /// SIMD minimum size threshold
34    pub simd_min_size: usize,
35    /// Enable semantic type detection
36    pub enable_semantics: bool,
37}
38
39/// Configuration for streaming operations
40#[derive(Debug, Clone)]
41pub struct StreamingConfig {
42    /// Maximum frame size in bytes
43    pub max_frame_size: usize,
44    /// Default chunk size for processing
45    pub default_chunk_size: usize,
46    /// Timeout for operations in milliseconds
47    pub operation_timeout_ms: u64,
48    /// Maximum bandwidth in bytes per second
49    pub max_bandwidth_bps: u64,
50}
51
52/// Configuration for SIMD acceleration
53#[derive(Debug, Clone)]
54pub struct SimdConfig {
55    /// Batch size for SIMD operations
56    pub batch_size: usize,
57    /// Initial capacity for SIMD buffers
58    pub initial_capacity: usize,
59    /// AVX-512 alignment size in bytes
60    pub avx512_alignment: usize,
61    /// Chunk size for vectorized operations
62    pub vectorized_chunk_size: usize,
63    /// Enable statistics collection
64    pub enable_stats: bool,
65}
66
67impl Default for ParserConfig {
68    fn default() -> Self {
69        Self {
70            max_input_size_mb: 100,
71            buffer_initial_capacity: 8192, // 8KB
72            simd_min_size: 4096,           // 4KB
73            enable_semantics: true,
74        }
75    }
76}
77
78impl Default for StreamingConfig {
79    fn default() -> Self {
80        Self {
81            max_frame_size: 64 * 1024, // 64KB
82            default_chunk_size: 1024,
83            operation_timeout_ms: 5000,   // 5 seconds
84            max_bandwidth_bps: 1_000_000, // 1MB/s
85        }
86    }
87}
88
89impl Default for SimdConfig {
90    fn default() -> Self {
91        Self {
92            batch_size: 100,
93            initial_capacity: 8192, // 8KB
94            avx512_alignment: 64,
95            vectorized_chunk_size: 32,
96            enable_stats: false,
97        }
98    }
99}
100
101/// Configuration profiles for different use cases
102impl PjsConfig {
103    /// Configuration optimized for low latency
104    pub fn low_latency() -> Self {
105        Self {
106            security: SecurityConfig::development(),
107            compression: CompressionConfig::default(),
108            parser: ParserConfig {
109                max_input_size_mb: 10,
110                buffer_initial_capacity: 4096, // 4KB
111                simd_min_size: 2048,           // 2KB
112                enable_semantics: false,       // Disable for speed
113            },
114            streaming: StreamingConfig {
115                max_frame_size: 16 * 1024, // 16KB
116                default_chunk_size: 512,
117                operation_timeout_ms: 1000,    // 1 second
118                max_bandwidth_bps: 10_000_000, // 10MB/s
119            },
120            simd: SimdConfig {
121                batch_size: 50,
122                initial_capacity: 4096, // 4KB
123                avx512_alignment: 64,
124                vectorized_chunk_size: 16,
125                enable_stats: false,
126            },
127        }
128    }
129
130    /// Configuration optimized for high throughput
131    pub fn high_throughput() -> Self {
132        Self {
133            security: SecurityConfig::high_throughput(),
134            compression: CompressionConfig::default(),
135            parser: ParserConfig {
136                max_input_size_mb: 1000,        // 1GB
137                buffer_initial_capacity: 32768, // 32KB
138                simd_min_size: 8192,            // 8KB
139                enable_semantics: true,
140            },
141            streaming: StreamingConfig {
142                max_frame_size: 256 * 1024, // 256KB
143                default_chunk_size: 4096,
144                operation_timeout_ms: 30000,    // 30 seconds
145                max_bandwidth_bps: 100_000_000, // 100MB/s
146            },
147            simd: SimdConfig {
148                batch_size: 500,
149                initial_capacity: 32768, // 32KB
150                avx512_alignment: 64,
151                vectorized_chunk_size: 64,
152                enable_stats: true,
153            },
154        }
155    }
156
157    /// Configuration optimized for mobile/constrained devices
158    pub fn mobile() -> Self {
159        Self {
160            security: SecurityConfig::low_memory(),
161            compression: CompressionConfig {
162                min_array_length: 1,
163                min_string_length: 2,
164                min_frequency_count: 1,
165                uuid_compression_potential: 0.5,
166                string_dict_threshold: 25.0, // Lower threshold
167                delta_threshold: 15.0,       // Lower threshold
168                min_delta_potential: 0.2,
169                run_length_threshold: 10.0, // Lower threshold
170                min_compression_potential: 0.3,
171                min_numeric_sequence_size: 2,
172            },
173            parser: ParserConfig {
174                max_input_size_mb: 10,
175                buffer_initial_capacity: 2048, // 2KB
176                simd_min_size: 1024,           // 1KB
177                enable_semantics: false,
178            },
179            streaming: StreamingConfig {
180                max_frame_size: 8 * 1024, // 8KB
181                default_chunk_size: 256,
182                operation_timeout_ms: 10000, // 10 seconds
183                max_bandwidth_bps: 100_000,  // 100KB/s
184            },
185            simd: SimdConfig {
186                batch_size: 25,
187                initial_capacity: 2048, // 2KB
188                avx512_alignment: 32,   // Smaller alignment
189                vectorized_chunk_size: 8,
190                enable_stats: false,
191            },
192        }
193    }
194}
195
196#[cfg(test)]
197mod tests {
198    use super::*;
199
200    #[test]
201    fn test_default_config() {
202        let config = PjsConfig::default();
203        assert_eq!(config.parser.max_input_size_mb, 100);
204        assert_eq!(config.streaming.max_frame_size, 64 * 1024);
205        assert_eq!(config.simd.batch_size, 100);
206    }
207
208    #[test]
209    fn test_low_latency_profile() {
210        let config = PjsConfig::low_latency();
211        assert_eq!(config.streaming.max_frame_size, 16 * 1024);
212        assert!(!config.parser.enable_semantics);
213        assert_eq!(config.streaming.operation_timeout_ms, 1000);
214    }
215
216    #[test]
217    fn test_high_throughput_profile() {
218        let config = PjsConfig::high_throughput();
219        assert_eq!(config.streaming.max_frame_size, 256 * 1024);
220        assert!(config.parser.enable_semantics);
221        assert!(config.simd.enable_stats);
222    }
223
224    #[test]
225    fn test_mobile_profile() {
226        let config = PjsConfig::mobile();
227        assert_eq!(config.streaming.max_frame_size, 8 * 1024);
228        assert_eq!(config.compression.string_dict_threshold, 25.0);
229        assert_eq!(config.simd.vectorized_chunk_size, 8);
230    }
231
232    #[test]
233    fn test_compression_with_custom_config() {
234        use crate::compression::{CompressionConfig, SchemaAnalyzer};
235        use serde_json::json;
236
237        // Create custom compression config with lower thresholds
238        let compression_config = CompressionConfig {
239            string_dict_threshold: 10.0, // Lower threshold for testing
240            min_frequency_count: 1,
241            ..Default::default()
242        };
243
244        let mut analyzer = SchemaAnalyzer::with_config(compression_config);
245
246        // Test data that should trigger dictionary compression with low threshold
247        let data = json!({
248            "users": [
249                {"status": "active", "role": "user"},
250                {"status": "active", "role": "user"}
251            ]
252        });
253
254        let strategy = analyzer.analyze(&data).unwrap();
255
256        // With lower threshold, should detect dictionary compression opportunity
257        match strategy {
258            crate::compression::CompressionStrategy::Dictionary { .. }
259            | crate::compression::CompressionStrategy::Hybrid { .. } => {
260                // Expected with low threshold
261            }
262            _ => {
263                // Also acceptable, depends on specific data characteristics
264            }
265        }
266    }
267}