parser_bench.rs
1 use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 use korni::Korni; 3 4 fn benchmark_parser(c: &mut Criterion) { 5 let simple_env = "KEY=value\nANOTHER_KEY=another_value\n# Comment\nEXPORTED=true"; 6 7 let mut group = c.benchmark_group("parser"); 8 9 group.bench_function("simple_env", |b| { 10 b.iter(|| { 11 let _ = Korni::from_str(black_box(simple_env)).parse(); 12 }) 13 }); 14 15 // Create a larger synthetic payload 16 let mut large_env = String::new(); 17 for i in 0..1000 { 18 large_env.push_str(&format!("KEY_{}=value_{}\n", i, i)); 19 large_env.push_str(&format!("# Comment {}\n", i)); 20 large_env.push_str(&format!("QUOTED_{}=\"some quoted value with number {}\"\n", i, i)); 21 } 22 23 group.bench_function("large_env_1k_lines", |b| { 24 b.iter(|| { 25 let _ = Korni::from_str(black_box(&large_env)).parse(); 26 }) 27 }); 28 29 // Benchmark just the iterator (parsing without HashMap construction) 30 group.bench_function("iterator_only_large", |b| { 31 b.iter(|| { 32 let builder = Korni::from_str(black_box(&large_env)); 33 // We need to bypass .parse() which constructs Environment 34 // So we use parsing logic directly or a helper if available, 35 // but .parse() is the public API. 36 // Let's benchmark the high-level API as that's what users use. 37 let _ = builder.parse(); 38 }) 39 }); 40 41 group.finish(); 42 } 43 44 fn benchmark_error_handling(c: &mut Criterion) { 45 let mut error_env = String::new(); 46 for i in 0..1000 { 47 // Mix of valid and invalid entries 48 if i % 10 == 0 { 49 // Invalid: space around equals 50 error_env.push_str(&format!("KEY_{} = value_{}\n", i, i)); 51 } else if i % 7 == 0 { 52 // Invalid: starts with digit 53 error_env.push_str(&format!("{}KEY=value_{}\n", i, i)); 54 } else if i % 5 == 0 { 55 // Invalid: double equals 56 error_env.push_str(&format!("KEY_{}==value_{}\n", i, i)); 57 } else { 58 // Valid 59 error_env.push_str(&format!("KEY_{}=value_{}\n", i, i)); 60 } 61 } 62 63 let mut group = c.benchmark_group("error_handling"); 64 65 group.bench_function("error_heavy_1k_lines", |b| { 66 b.iter(|| { 67 let _ = Korni::from_str(black_box(&error_env)).parse(); 68 }) 69 }); 70 71 group.finish(); 72 } 73 74 fn benchmark_quote_types(c: &mut Criterion) { 75 let mut single_quoted = String::new(); 76 let mut double_quoted = String::new(); 77 let mut unquoted = String::new(); 78 79 for i in 0..1000 { 80 single_quoted.push_str(&format!("KEY_{}='value_{}'\n", i, i)); 81 double_quoted.push_str(&format!("KEY_{}=\"value_{}\"\n", i, i)); 82 unquoted.push_str(&format!("KEY_{}=value_{}\n", i, i)); 83 } 84 85 let mut group = c.benchmark_group("quote_types"); 86 87 group.bench_function("single_quoted_1k_lines", |b| { 88 b.iter(|| { 89 let _ = Korni::from_str(black_box(&single_quoted)).parse(); 90 }) 91 }); 92 93 group.bench_function("double_quoted_1k_lines", |b| { 94 b.iter(|| { 95 let _ = Korni::from_str(black_box(&double_quoted)).parse(); 96 }) 97 }); 98 99 group.bench_function("unquoted_1k_lines", |b| { 100 b.iter(|| { 101 let _ = Korni::from_str(black_box(&unquoted)).parse(); 102 }) 103 }); 104 105 group.finish(); 106 } 107 108 fn benchmark_comment_heavy(c: &mut Criterion) { 109 let mut comment_heavy = String::new(); 110 111 for i in 0..1000 { 112 comment_heavy.push_str(&format!("# This is comment number {}\n", i)); 113 comment_heavy.push_str(&format!("# With multiple lines\n")); 114 comment_heavy.push_str(&format!("KEY_{}=value_{}\n", i, i)); 115 } 116 117 let mut group = c.benchmark_group("comments"); 118 119 group.bench_function("comment_heavy_1k_lines", |b| { 120 b.iter(|| { 121 let _ = Korni::from_str(black_box(&comment_heavy)).parse(); 122 }) 123 }); 124 125 group.bench_function("comment_heavy_with_tracking", |b| { 126 b.iter(|| { 127 let _ = Korni::from_str(black_box(&comment_heavy)) 128 .preserve_comments() 129 .track_positions() 130 .parse(); 131 }) 132 }); 133 134 group.finish(); 135 } 136 137 criterion_group!(benches, benchmark_parser, benchmark_error_handling, benchmark_quote_types, benchmark_comment_heavy); 138 criterion_main!(benches);