1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::time::Duration;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct ParserConfig {
13 pub backend: ParserBackend,
15
16 pub timeout: Duration,
18
19 pub max_expression_depth: u32,
21
22 pub max_collection_size: u32,
24
25 pub max_string_length: u32,
27
28 pub max_parameters: u32,
30
31 pub strict_validation: bool,
33
34 pub allow_experimental: bool,
36
37 pub backend_options: HashMap<String, serde_json::Value>,
39
40 pub features: Vec<ParserFeature>,
42
43 pub memory_limits: MemoryLimits,
45
46 pub performance: PerformanceSettings,
48
49 pub error_handling: ErrorHandlingSettings,
51
52 pub memory_settings: MemorySettings,
54
55 pub security_settings: SecuritySettings,
57}
58
59#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61pub enum ParserBackend {
62 Nom,
64
65 Auto,
70
71 Custom(String),
73}
74
75#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
77pub enum ParserFeature {
78 Streaming,
80
81 ErrorRecovery,
83
84 SyntaxHighlighting,
86
87 CodeCompletion,
89
90 AstTransformation,
92
93 CustomOperators,
95
96 Parallel,
98
99 Caching,
101
102 OnlineValidation,
104
105 Profiling,
107}
108
109#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
111pub struct MemoryLimits {
112 pub max_ast_size: u64,
114
115 pub max_temp_memory: u64,
117
118 pub max_stack_depth: u32,
120
121 pub max_cache_entries: u32,
123}
124
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
127pub struct PerformanceSettings {
128 pub worker_threads: u32,
130
131 pub stream_buffer_size: u32,
133
134 pub enable_caching: bool,
136
137 pub cache_ttl: Duration,
139
140 pub enable_jit: bool,
142
143 pub optimization_level: u8,
145}
146
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
149pub struct ErrorHandlingSettings {
150 pub max_errors: u32,
152
153 pub continue_on_error: bool,
155
156 pub error_context_lines: u32,
158
159 pub include_suggestions: bool,
161
162 pub collect_error_stats: bool,
164}
165
166#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
168pub struct MemorySettings {
169 pub max_parser_memory: u64,
171
172 pub allocation_strategy: MemoryAllocationStrategy,
174
175 pub enable_memory_pooling: bool,
177
178 pub memory_pool_size: usize,
180}
181
182#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
184pub enum MemoryAllocationStrategy {
185 Standard,
187 Pooled,
189 Arena,
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
195pub struct SecuritySettings {
196 pub max_query_depth: u32,
198
199 pub max_token_count: u32,
201
202 pub enable_input_sanitization: bool,
204
205 pub restrict_dangerous_operations: bool,
207
208 pub blocked_keywords: Vec<String>,
210}
211
212impl Default for ParserConfig {
213 fn default() -> Self {
214 Self {
215 backend: ParserBackend::Auto,
216 timeout: Duration::from_secs(30),
217 max_expression_depth: 100,
218 max_collection_size: 10_000,
219 max_string_length: 1_000_000,
220 max_parameters: 1000,
221 strict_validation: true,
222 allow_experimental: false,
223 backend_options: HashMap::new(),
224 features: vec![
225 ParserFeature::ErrorRecovery,
226 ParserFeature::OnlineValidation,
227 ],
228 memory_limits: MemoryLimits::default(),
229 performance: PerformanceSettings::default(),
230 error_handling: ErrorHandlingSettings::default(),
231 memory_settings: MemorySettings::default(),
232 security_settings: SecuritySettings::default(),
233 }
234 }
235}
236
237impl Default for MemoryLimits {
238 fn default() -> Self {
239 Self {
240 max_ast_size: 100 * 1024 * 1024, max_temp_memory: 50 * 1024 * 1024, max_stack_depth: 1000,
243 max_cache_entries: 10_000,
244 }
245 }
246}
247
248impl Default for PerformanceSettings {
249 fn default() -> Self {
250 Self {
251 worker_threads: num_cpus::get() as u32,
252 stream_buffer_size: 64 * 1024, enable_caching: true,
254 cache_ttl: Duration::from_secs(300), enable_jit: false,
256 optimization_level: 2,
257 }
258 }
259}
260
261impl Default for ErrorHandlingSettings {
262 fn default() -> Self {
263 Self {
264 max_errors: 100,
265 continue_on_error: true,
266 error_context_lines: 3,
267 include_suggestions: true,
268 collect_error_stats: false,
269 }
270 }
271}
272
273impl Default for MemorySettings {
274 fn default() -> Self {
275 Self {
276 max_parser_memory: 50 * 1024 * 1024, allocation_strategy: MemoryAllocationStrategy::Standard,
278 enable_memory_pooling: false,
279 memory_pool_size: 1024,
280 }
281 }
282}
283
284impl Default for SecuritySettings {
285 fn default() -> Self {
286 Self {
287 max_query_depth: 100,
288 max_token_count: 10_000,
289 enable_input_sanitization: true,
290 restrict_dangerous_operations: true,
291 blocked_keywords: vec![],
292 }
293 }
294}
295
296impl ParserConfig {
297 pub fn new() -> Self {
299 Self::default()
300 }
301
302 pub fn fast() -> Self {
307 Self {
308 backend: ParserBackend::Nom,
309 timeout: Duration::from_secs(10),
310 strict_validation: false,
311 features: vec![
312 ParserFeature::Parallel,
313 ParserFeature::Caching,
314 ParserFeature::Streaming,
315 ],
316 performance: PerformanceSettings {
317 optimization_level: 3,
318 enable_jit: true,
319 worker_threads: (num_cpus::get() as u32).max(2),
320 ..Default::default()
321 },
322 ..Default::default()
323 }
324 }
325
326 pub fn strict() -> Self {
328 Self {
329 backend: ParserBackend::Nom,
330 strict_validation: true,
331 allow_experimental: false,
332 features: vec![
333 ParserFeature::ErrorRecovery,
334 ParserFeature::OnlineValidation,
335 ParserFeature::Profiling,
336 ],
337 error_handling: ErrorHandlingSettings {
338 max_errors: 1,
339 continue_on_error: false,
340 include_suggestions: true,
341 collect_error_stats: true,
342 ..Default::default()
343 },
344 ..Default::default()
345 }
346 }
347
348 pub fn development() -> Self {
350 Self {
351 backend: ParserBackend::Auto,
352 allow_experimental: true,
353 features: vec![
354 ParserFeature::ErrorRecovery,
355 ParserFeature::AstTransformation,
356 ParserFeature::OnlineValidation,
357 ParserFeature::Profiling,
358 ],
359 error_handling: ErrorHandlingSettings {
360 continue_on_error: true,
361 include_suggestions: true,
362 collect_error_stats: true,
363 ..Default::default()
364 },
365 ..Default::default()
366 }
367 }
368
369 pub fn minimal() -> Self {
371 Self {
372 backend: ParserBackend::Nom,
373 timeout: Duration::from_secs(5),
374 max_expression_depth: 50,
375 max_collection_size: 1000,
376 max_string_length: 10_000,
377 max_parameters: 100,
378 strict_validation: false,
379 features: vec![],
380 memory_limits: MemoryLimits {
381 max_ast_size: 10 * 1024 * 1024, max_temp_memory: 5 * 1024 * 1024, max_stack_depth: 100,
384 max_cache_entries: 100,
385 },
386 performance: PerformanceSettings {
387 worker_threads: 1,
388 enable_caching: false,
389 optimization_level: 1,
390 ..Default::default()
391 },
392 error_handling: ErrorHandlingSettings {
393 max_errors: 10,
394 error_context_lines: 1,
395 include_suggestions: false,
396 collect_error_stats: false,
397 ..Default::default()
398 },
399 ..Default::default()
400 }
401 }
402
403 pub fn with_backend(mut self, backend: ParserBackend) -> Self {
405 self.backend = backend;
406 self
407 }
408
409 pub fn with_timeout(mut self, timeout: Duration) -> Self {
411 self.timeout = timeout;
412 self
413 }
414
415 pub fn with_strict_validation(mut self, strict: bool) -> Self {
417 self.strict_validation = strict;
418 self
419 }
420
421 pub fn with_feature(mut self, feature: ParserFeature) -> Self {
423 if !self.features.contains(&feature) {
424 self.features.push(feature);
425 }
426 self
427 }
428
429 pub fn has_feature(&self, feature: &ParserFeature) -> bool {
431 self.features.contains(feature)
432 }
433
434 pub fn validate(&self) -> Result<(), String> {
436 if self.timeout.is_zero() {
439 return Err("Timeout must be greater than 0".to_string());
440 }
441 if self.max_expression_depth == 0 {
442 return Err("Max expression depth must be greater than 0".to_string());
443 }
444 if self.max_collection_size == 0 {
445 return Err("Max collection size must be greater than 0".to_string());
446 }
447 if self.memory_limits.max_ast_size == 0 {
448 return Err("Max AST size must be greater than 0".to_string());
449 }
450 if self.memory_limits.max_stack_depth == 0 {
451 return Err("Max stack depth must be greater than 0".to_string());
452 }
453 if self.performance.worker_threads == 0 {
454 return Err("Worker threads must be greater than 0".to_string());
455 }
456 if self.performance.stream_buffer_size < 1024 {
457 return Err("Stream buffer size should be at least 1KB for efficiency".to_string());
458 }
459 if self.performance.optimization_level > 3 {
460 return Err("Optimization level must be 0-3".to_string());
461 }
462 if self.error_handling.max_errors == 0 {
463 return Err("Max errors must be greater than 0".to_string());
464 }
465
466 if self.has_feature(&ParserFeature::Parallel) && self.performance.worker_threads == 1 {
467 return Err("Parallel parsing requires at least 2 worker threads. Use ParserConfig::fast() for automatic thread count adjustment.".to_string());
468 }
469
470 Ok(())
471 }
472}
473
474#[cfg(test)]
475mod tests {
476 use super::*;
477
478 #[test]
479 fn test_default_config() {
480 let config = ParserConfig::default();
481 assert!(matches!(config.backend, ParserBackend::Auto));
482 assert!(config.strict_validation);
483 assert!(!config.allow_experimental);
484 assert!(config.validate().is_ok());
485 }
486
487 #[test]
488 fn test_preset_configs() {
489 let fast = ParserConfig::fast();
490 assert!(matches!(fast.backend, ParserBackend::Nom));
491 assert!(!fast.strict_validation);
492 assert!(fast.validate().is_ok());
493
494 let strict = ParserConfig::strict();
495 assert!(matches!(strict.backend, ParserBackend::Nom));
496 assert!(strict.strict_validation);
497 assert!(strict.validate().is_ok());
498
499 let minimal = ParserConfig::minimal();
500 assert_eq!(minimal.memory_limits.max_ast_size, 10 * 1024 * 1024);
501 assert!(minimal.validate().is_ok());
502 }
503
504 #[test]
505 fn test_config_validation() {
506 let mut config = ParserConfig::default();
507 assert!(config.validate().is_ok());
508
509 config.timeout = Duration::from_secs(0);
510 assert!(config.validate().is_err());
511
512 config = ParserConfig::default();
513 config.performance.optimization_level = 5;
514 assert!(config.validate().is_err());
515 }
516
517 #[test]
518 fn test_sub_second_timeout_is_valid() {
519 let config = ParserConfig::default().with_timeout(Duration::from_millis(100));
522 assert!(config.validate().is_ok());
523 }
524
525 #[test]
526 fn test_feature_management() {
527 let mut config = ParserConfig::default();
528 assert!(!config.has_feature(&ParserFeature::Streaming));
529
530 config = config.with_feature(ParserFeature::Streaming);
531 assert!(config.has_feature(&ParserFeature::Streaming));
532 }
533
534 #[test]
535 fn test_parallel_requires_multiple_workers() {
536 let mut config = ParserConfig::minimal().with_feature(ParserFeature::Parallel);
537 config.performance.worker_threads = 1;
538 let err = config
539 .validate()
540 .expect_err("parallel parsing should require >1 worker");
541 assert!(err.contains("Parallel parsing requires at least 2 worker threads"));
542 }
543
544 #[test]
545 fn test_streaming_allowed_with_nom() {
546 let config = ParserConfig::strict().with_feature(ParserFeature::Streaming);
549 assert!(config.validate().is_ok());
550 }
551}