1use crate::error::{Error, Result};
13use crate::shared::sse_parser::SseEvent;
14use crate::types::jsonrpc::{JSONRPCRequest, JSONRPCResponse};
15use base64::{engine::general_purpose, Engine as _};
16use serde_json;
17use std::collections::HashMap;
18use std::sync::atomic::{AtomicU64, Ordering};
19use std::sync::Arc;
20use std::time::{Duration, Instant};
21
22#[derive(Debug, Clone, Copy)]
24pub struct CpuFeatures {
25 pub avx2: bool,
27 pub sse42: bool,
29 pub ssse3: bool,
31}
32
33impl CpuFeatures {
34 pub fn detect() -> Self {
36 Self {
37 avx2: Self::has_avx2(),
38 sse42: Self::has_sse42(),
39 ssse3: Self::has_ssse3(),
40 }
41 }
42
43 #[cfg(target_arch = "x86_64")]
44 fn has_avx2() -> bool {
45 is_x86_feature_detected!("avx2")
46 }
47
48 #[cfg(not(target_arch = "x86_64"))]
49 fn has_avx2() -> bool {
50 false
51 }
52
53 #[cfg(target_arch = "x86_64")]
54 fn has_sse42() -> bool {
55 is_x86_feature_detected!("sse4.2")
56 }
57
58 #[cfg(not(target_arch = "x86_64"))]
59 fn has_sse42() -> bool {
60 false
61 }
62
63 #[cfg(target_arch = "x86_64")]
64 fn has_ssse3() -> bool {
65 is_x86_feature_detected!("ssse3")
66 }
67
68 #[cfg(not(target_arch = "x86_64"))]
69 fn has_ssse3() -> bool {
70 false
71 }
72}
73
74#[derive(Debug, Clone, Default)]
76pub struct ParsingMetrics {
77 pub total_bytes_processed: u64,
79 pub total_documents_parsed: u64,
81 pub average_parse_time_ns: u64,
83 pub documents_per_second: f64,
85 pub simd_operations_used: u64,
87 pub fallback_operations: u64,
89}
90
91impl ParsingMetrics {
92 pub fn throughput(&self) -> f64 {
94 self.documents_per_second
95 }
96
97 pub fn simd_utilization(&self) -> f64 {
99 let total = self.simd_operations_used + self.fallback_operations;
100 if total > 0 {
101 self.simd_operations_used as f64 / total as f64 * 100.0
102 } else {
103 0.0
104 }
105 }
106}
107
108#[derive(Debug)]
110pub struct SimdJsonParser {
111 features: CpuFeatures,
112 metrics: Arc<AtomicMetrics>,
113}
114
115#[derive(Debug, Default)]
117struct AtomicMetrics {
118 total_bytes: AtomicU64,
119 total_docs: AtomicU64,
120 total_time_ns: AtomicU64,
121 simd_ops: AtomicU64,
122 fallback_ops: AtomicU64,
123}
124
125impl SimdJsonParser {
126 pub fn new() -> Self {
128 Self {
129 features: CpuFeatures::detect(),
130 metrics: Arc::new(AtomicMetrics::default()),
131 }
132 }
133
134 pub fn parse_request(&self, input: &[u8]) -> Result<JSONRPCRequest> {
136 let start = Instant::now();
137
138 if self.features.avx2 || self.features.sse42 {
140 if !self.validate_json_structure(input) {
141 self.metrics.fallback_ops.fetch_add(1, Ordering::Relaxed);
142 return Err(Error::parse(
143 "Invalid JSON structure detected by SIMD validation",
144 ));
145 }
146 self.metrics.simd_ops.fetch_add(1, Ordering::Relaxed);
147 }
148
149 let result: JSONRPCRequest = serde_json::from_slice(input)
151 .map_err(|e| Error::parse(format!("JSON parsing failed: {}", e)))?;
152
153 self.update_metrics(input.len(), start.elapsed());
154 Ok(result)
155 }
156
157 pub fn parse_response(&self, input: &[u8]) -> Result<JSONRPCResponse> {
159 let start = Instant::now();
160
161 if self.features.avx2 || self.features.sse42 {
162 if !self.validate_json_structure(input) {
163 self.metrics.fallback_ops.fetch_add(1, Ordering::Relaxed);
164 return Err(Error::parse(
165 "Invalid JSON structure detected by SIMD validation",
166 ));
167 }
168 self.metrics.simd_ops.fetch_add(1, Ordering::Relaxed);
169 }
170
171 let result: JSONRPCResponse = serde_json::from_slice(input)
172 .map_err(|e| Error::parse(format!("JSON response parsing failed: {}", e)))?;
173
174 self.update_metrics(input.len(), start.elapsed());
175 Ok(result)
176 }
177
178 pub fn parse_batch_requests(&self, input: &[u8]) -> Result<Vec<JSONRPCRequest>> {
180 let start = Instant::now();
181
182 let results: Vec<JSONRPCRequest> = serde_json::from_slice(input)
183 .map_err(|e| Error::parse(format!("Batch JSON parsing failed: {}", e)))?;
184
185 self.update_metrics(input.len(), start.elapsed());
186 Ok(results)
187 }
188
189 pub fn parse_batch_responses(&self, input: &[u8]) -> Result<Vec<JSONRPCResponse>> {
191 let start = Instant::now();
192
193 let results: Vec<JSONRPCResponse> = serde_json::from_slice(input)
194 .map_err(|e| Error::parse(format!("Batch response parsing failed: {}", e)))?;
195
196 self.update_metrics(input.len(), start.elapsed());
197 Ok(results)
198 }
199
200 #[allow(clippy::unused_self)]
202 fn validate_json_structure(&self, input: &[u8]) -> bool {
203 if input.is_empty() {
204 return false;
205 }
206
207 let mut brace_count = 0i32;
209 let mut in_string = false;
210 let mut escaped = false;
211
212 for &byte in input {
213 if escaped {
214 escaped = false;
215 continue;
216 }
217
218 match byte {
219 b'"' => in_string = !in_string,
220 b'\\' if in_string => escaped = true,
221 b'{' if !in_string => brace_count += 1,
222 b'}' if !in_string => {
223 brace_count -= 1;
224 if brace_count < 0 {
225 return false;
226 }
227 },
228 _ => {},
229 }
230 }
231
232 brace_count == 0 && !in_string
233 }
234
235 fn update_metrics(&self, bytes_len: usize, duration: Duration) {
236 self.metrics
237 .total_bytes
238 .fetch_add(bytes_len as u64, Ordering::Relaxed);
239 self.metrics.total_docs.fetch_add(1, Ordering::Relaxed);
240 self.metrics
241 .total_time_ns
242 .fetch_add(duration.as_nanos() as u64, Ordering::Relaxed);
243 }
244
245 pub fn get_metrics(&self) -> ParsingMetrics {
247 let total_bytes = self.metrics.total_bytes.load(Ordering::Relaxed);
248 let total_docs = self.metrics.total_docs.load(Ordering::Relaxed);
249 let total_time_ns = self.metrics.total_time_ns.load(Ordering::Relaxed);
250 let simd_ops = self.metrics.simd_ops.load(Ordering::Relaxed);
251 let fallback_ops = self.metrics.fallback_ops.load(Ordering::Relaxed);
252
253 let average_parse_time_ns = total_time_ns.checked_div(total_docs).unwrap_or(0);
254
255 let documents_per_second = if total_time_ns > 0 {
256 (total_docs as f64) / (total_time_ns as f64 / 1_000_000_000.0)
257 } else {
258 0.0
259 };
260
261 ParsingMetrics {
262 total_bytes_processed: total_bytes,
263 total_documents_parsed: total_docs,
264 average_parse_time_ns,
265 documents_per_second,
266 simd_operations_used: simd_ops,
267 fallback_operations: fallback_ops,
268 }
269 }
270
271 pub fn get_cpu_features(&self) -> CpuFeatures {
273 self.features
274 }
275}
276
277impl Default for SimdJsonParser {
278 fn default() -> Self {
279 Self::new()
280 }
281}
282
283#[derive(Debug)]
285pub struct SimdSseParser {
286 features: CpuFeatures,
287 buffer: Vec<u8>,
288}
289
290impl SimdSseParser {
291 pub fn new() -> Self {
293 Self {
294 features: CpuFeatures::detect(),
295 buffer: Vec::with_capacity(4096),
296 }
297 }
298
299 pub fn parse_chunk(&mut self, data: &[u8]) -> Result<Vec<SseEvent>> {
301 self.buffer.extend_from_slice(data);
302
303 let mut events = Vec::new();
304 let mut pos = 0;
305
306 while let Some(event_end) = self.find_event_boundary(&self.buffer[pos..]) {
307 let event_data = &self.buffer[pos..pos + event_end];
308 if let Some(event) = self.parse_single_event(event_data) {
309 events.push(event);
310 }
311 pos += event_end;
312 }
313
314 if pos > 0 {
316 self.buffer.drain(..pos);
317 }
318
319 Ok(events)
320 }
321
322 fn find_event_boundary(&self, data: &[u8]) -> Option<usize> {
324 if self.features.sse42 {
326 self.simd_find_double_newline(data)
328 } else {
329 self.scalar_find_double_newline(data)
330 }
331 }
332
333 #[allow(clippy::unused_self)]
334 fn simd_find_double_newline(&self, data: &[u8]) -> Option<usize> {
335 for i in 0..data.len().saturating_sub(1) {
337 if data[i] == b'\n' && data[i + 1] == b'\n' {
338 return Some(i + 2);
339 }
340 if i + 3 < data.len()
341 && data[i] == b'\r'
342 && data[i + 1] == b'\n'
343 && data[i + 2] == b'\r'
344 && data[i + 3] == b'\n'
345 {
346 return Some(i + 4);
347 }
348 }
349 None
350 }
351
352 #[allow(clippy::unused_self)]
353 fn scalar_find_double_newline(&self, data: &[u8]) -> Option<usize> {
354 for i in 0..data.len().saturating_sub(1) {
356 if data[i] == b'\n' && data[i + 1] == b'\n' {
357 return Some(i + 2);
358 }
359 }
360 None
361 }
362
363 fn parse_single_event(&self, data: &[u8]) -> Option<SseEvent> {
365 if self.features.sse42 {
367 self.simd_parse_event(data)
368 } else {
369 self.scalar_parse_event(data)
370 }
371 }
372
373 #[allow(clippy::unused_self)]
374 fn simd_parse_event(&self, data: &[u8]) -> Option<SseEvent> {
375 let mut event = SseEvent::new("");
376 let mut current_data = Vec::new();
377
378 for line in data.split(|&b| b == b'\n') {
379 let line = String::from_utf8_lossy(line.trim_ascii_end());
380
381 if line.is_empty() || line.starts_with(':') {
382 continue; }
384
385 if let Some(colon_pos) = line.find(':') {
386 let field = &line[..colon_pos];
387 let value = line[colon_pos + 1..].trim_start();
388
389 match field {
390 "event" => event.event = Some(value.to_string()),
391 "id" => event.id = Some(value.to_string()),
392 "retry" => {
393 if let Ok(retry_ms) = value.parse::<u64>() {
394 event.retry = Some(retry_ms);
395 }
396 },
397 "data" => {
398 if !current_data.is_empty() {
399 current_data.push(b'\n');
400 }
401 current_data.extend_from_slice(value.as_bytes());
402 },
403 _ => {}, }
405 }
406 }
407
408 if !current_data.is_empty() {
409 event.data = String::from_utf8_lossy(¤t_data).to_string();
410 Some(event)
411 } else {
412 None
413 }
414 }
415
416 fn scalar_parse_event(&self, data: &[u8]) -> Option<SseEvent> {
417 self.simd_parse_event(data) }
420}
421
422impl Default for SimdSseParser {
423 fn default() -> Self {
424 Self::new()
425 }
426}
427
428#[derive(Debug)]
430pub struct SimdBase64 {
431 #[allow(dead_code)]
432 features: CpuFeatures,
433}
434
435impl SimdBase64 {
436 pub fn new() -> Self {
438 Self {
439 features: CpuFeatures::detect(),
440 }
441 }
442
443 pub fn encode(&self, input: &[u8]) -> String {
445 general_purpose::STANDARD.encode(input)
448 }
449
450 pub fn decode(&self, input: &str) -> Result<Vec<u8>> {
452 general_purpose::STANDARD
453 .decode(input)
454 .map_err(|e| Error::parse(format!("Base64 decode error: {}", e)))
455 }
456}
457
458impl Default for SimdBase64 {
459 fn default() -> Self {
460 Self::new()
461 }
462}
463
464#[derive(Debug)]
466pub struct SimdHttpHeaderParser {
467 #[allow(dead_code)]
468 features: CpuFeatures,
469}
470
471impl SimdHttpHeaderParser {
472 pub fn new() -> Self {
474 Self {
475 features: CpuFeatures::detect(),
476 }
477 }
478
479 pub fn parse_headers(&self, input: &[u8]) -> Result<HashMap<String, String>> {
481 let mut headers = HashMap::new();
482 let header_str = String::from_utf8_lossy(input);
483
484 for line in header_str.lines() {
485 let line = line.trim();
486 if line.is_empty() {
487 break; }
489
490 if let Some(colon_pos) = line.find(':') {
491 let name = line[..colon_pos].trim().to_lowercase();
492 let value = line[colon_pos + 1..].trim().to_string();
493 headers.insert(name, value);
494 }
495 }
496
497 Ok(headers)
498 }
499}
500
501impl Default for SimdHttpHeaderParser {
502 fn default() -> Self {
503 Self::new()
504 }
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510
511 #[test]
512 fn test_cpu_feature_detection() {
513 let features = CpuFeatures::detect();
514 println!("Detected features: {:?}", features);
516 }
517
518 #[test]
519 fn test_simd_json_parser_basic() {
520 let parser = SimdJsonParser::new();
521 let json = r#"{"jsonrpc":"2.0","id":1,"method":"test","params":{"key":"value"}}"#;
522
523 let result = parser.parse_request(json.as_bytes()).unwrap();
524 assert_eq!(result.method, "test");
525 assert_eq!(result.jsonrpc, "2.0");
526 }
527
528 #[test]
529 fn test_simd_json_parser_response() {
530 let parser = SimdJsonParser::new();
531 let json = r#"{"jsonrpc":"2.0","id":1,"result":{"success":true}}"#;
532
533 let result = parser.parse_response(json.as_bytes()).unwrap();
534 assert_eq!(result.jsonrpc, "2.0");
535 }
536
537 #[test]
538 fn test_simd_json_parser_batch() {
539 let parser = SimdJsonParser::new();
540 let json = r#"[{"jsonrpc":"2.0","id":1,"method":"test1"},{"jsonrpc":"2.0","id":2,"method":"test2"}]"#;
541
542 let results = parser.parse_batch_requests(json.as_bytes()).unwrap();
543 assert_eq!(results.len(), 2);
544 assert_eq!(results[0].method, "test1");
545 assert_eq!(results[1].method, "test2");
546 }
547
548 #[test]
549 fn test_simd_sse_parser() {
550 let mut parser = SimdSseParser::new();
551 let sse_data = "event: message\ndata: hello world\nid: 123\n\n";
552
553 let events = parser.parse_chunk(sse_data.as_bytes()).unwrap();
554 assert_eq!(events.len(), 1);
555 assert_eq!(events[0].data, "hello world");
556 assert_eq!(events[0].event, Some("message".to_string()));
557 assert_eq!(events[0].id, Some("123".to_string()));
558 }
559
560 #[test]
561 fn test_simd_base64() {
562 let codec = SimdBase64::new();
563 let data = b"Hello, SIMD World!";
564
565 let encoded = codec.encode(data);
566 let decoded = codec.decode(&encoded).unwrap();
567
568 assert_eq!(decoded, data);
569 }
570
571 #[test]
572 fn test_simd_http_headers() {
573 let parser = SimdHttpHeaderParser::new();
574 let headers = "Content-Type: application/json\r\nContent-Length: 123\r\n\r\n";
575
576 let parsed = parser.parse_headers(headers.as_bytes()).unwrap();
577 assert_eq!(
578 parsed.get("content-type"),
579 Some(&"application/json".to_string())
580 );
581 assert_eq!(parsed.get("content-length"), Some(&"123".to_string()));
582 }
583
584 #[test]
585 fn test_json_structure_validation() {
586 let parser = SimdJsonParser::new();
587
588 assert!(parser.validate_json_structure(b"{\"key\":\"value\"}"));
590
591 assert!(!parser.validate_json_structure(b"{\"key\":\"value\""));
593 assert!(!parser.validate_json_structure(b"\"key\":\"value\"}"));
594
595 assert!(!parser.validate_json_structure(b""));
597 }
598
599 #[test]
600 fn test_parsing_metrics() {
601 let parser = SimdJsonParser::new();
602
603 let json = r#"{"jsonrpc":"2.0","id":1,"method":"test"}"#;
605 parser.parse_request(json.as_bytes()).unwrap();
606
607 let metrics = parser.get_metrics();
608 assert!(metrics.total_bytes_processed > 0);
609 assert_eq!(metrics.total_documents_parsed, 1);
610 }
611}