//! Performance benchmarks for core operations. //! //! Run with: `cargo bench` //! First run establishes baseline. Subsequent runs report regressions. use std::fs; use std::path::PathBuf; use criterion::{Criterion, criterion_group, criterion_main}; fn fixture_path(name: &str) -> PathBuf { let manifest_dir = env!("CARGO_MANIFEST_DIR"); PathBuf::from(manifest_dir) .join("tests") .join("fixtures") .join(name) } fn load_petstore_json() -> serde_json::Value { let path = fixture_path("petstore.json"); let bytes = fs::read(&path).expect("failed to read petstore.json fixture"); serde_json::from_slice(&bytes).expect("failed to parse petstore.json") } fn bench_json_parse(c: &mut Criterion) { let path = fixture_path("petstore.json"); let bytes = fs::read(&path).expect("failed to read petstore.json fixture"); c.bench_function("parse_petstore_json", |b| { b.iter(|| { let _: serde_json::Value = serde_json::from_slice(&bytes).expect("parse failed"); }); }); } fn bench_build_index(c: &mut Criterion) { let raw_json = load_petstore_json(); c.bench_function("build_index_petstore", |b| { b.iter(|| { // Simulate endpoint extraction (mirrors build_index core logic) if let Some(paths) = raw_json.get("paths").and_then(|v| v.as_object()) { let mut endpoints = Vec::new(); for (path, methods) in paths { if let Some(methods_map) = methods.as_object() { for (method, _op) in methods_map { endpoints.push((path.clone(), method.clone())); } } } assert!(!endpoints.is_empty()); } }); }); } fn bench_hash_computation(c: &mut Criterion) { let path = fixture_path("petstore.json"); let bytes = fs::read(&path).expect("failed to read petstore.json"); c.bench_function("sha256_petstore", |b| { b.iter(|| { use sha2::{Digest, Sha256}; let mut hasher = Sha256::new(); hasher.update(&bytes); let _result = format!("sha256:{:x}", hasher.finalize()); }); }); } fn bench_json_pointer_resolution(c: &mut Criterion) { let raw_json = load_petstore_json(); c.bench_function("json_pointer_resolution", |b| { b.iter(|| { let _ = raw_json .pointer("/paths/~1pets/get/summary") .map(|v| v.as_str()); let _ = raw_json .pointer("/components/schemas/Pet") .map(|v| v.is_object()); let _ = raw_json.pointer("/info/title").map(|v| v.as_str()); }); }); } fn bench_search_scoring(c: &mut Criterion) { let raw_json = load_petstore_json(); // Pre-extract summaries for search simulation let mut summaries: Vec = Vec::new(); if let Some(paths) = raw_json.get("paths").and_then(|v| v.as_object()) { for (_path, methods) in paths { if let Some(methods_map) = methods.as_object() { for (_method, op) in methods_map { if let Some(summary) = op.get("summary").and_then(|v| v.as_str()) { summaries.push(summary.to_lowercase()); } } } } } c.bench_function("search_scoring_pet", |b| { let query = "pet"; b.iter(|| { let mut matches = 0u32; for summary in &summaries { if summary.contains(query) { matches += 1; } } assert!(matches > 0); }); }); } criterion_group!( benches, bench_json_parse, bench_build_index, bench_hash_computation, bench_json_pointer_resolution, bench_search_scoring, ); criterion_main!(benches);