# 11. `sequenceof_benchmark.rs` — Element vs SequenceOf benchmark
[← Example index](index.md) · [sequenceof_benchmark.rs on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/sequenceof_benchmark.rs)
Micro-benchmark comparing eager `Element`-based parsing against lazy
`SequenceOf` iteration for `SEQUENCE OF` structures. Demonstrates the
O(1) lazy-parse advantage for large collections.
## Source
```rust,ignore
//! Benchmark comparing Element vs SequenceOf for parsing
//!
//! This demonstrates the performance benefit of lazy SequenceOf over
//! eager Element parsing for SEQUENCE OF structures.
//!
//! Methodology:
//! 1. Create test data with varying sizes using SequenceOf::from_vec()
//! 2. Benchmark decoding with Element (eager Vec allocation)
//! 3. Benchmark decoding with SequenceOf (lazy iteration)
//! 4. Compare memory allocations and parse times
use std::hint::black_box;
use synta::types::SequenceOf;
use synta::{Decoder, Encoder, Encoding};
use synta::{Element, Integer};
/// Benchmark parsing with Element (eager parsing)
fn parse_with_element(data: &[u8]) -> Result<usize, Box<dyn std::error::Error>> {
let mut decoder = Decoder::new(data, Encoding::Der);
let elem = decoder.decode::<Element>()?;
// Count children to simulate actual use
let count = match elem {
Element::Sequence(seq) => seq.iter().count(),
_ => 0,
};
Ok(count)
}
/// Benchmark parsing with SequenceOf (lazy iteration)
fn parse_with_sequenceof(data: &[u8]) -> Result<usize, Box<dyn std::error::Error>> {
let mut decoder = Decoder::new(data, Encoding::Der);
let seq = decoder.decode::<SequenceOf<Integer>>()?;
// Iterate to simulate actual use
let count = seq.count();
Ok(count)
}
/// Benchmark parsing with SequenceOf but collect to Vec
fn parse_with_sequenceof_collect(data: &[u8]) -> Result<usize, Box<dyn std::error::Error>> {
let mut decoder = Decoder::new(data, Encoding::Der);
let seq = decoder.decode::<SequenceOf<Integer>>()?;
// Collect to Vec (similar to Element behavior)
let vec = seq.collect_vec()?;
Ok(vec.len())
}
/// Create test data with N integer elements
fn create_test_data(num_elements: usize) -> Vec<u8> {
let elements: Vec<Integer> = (0..num_elements).map(|i| Integer::from(i as i64)).collect();
let seq = SequenceOf::from_vec(elements).expect("Failed to create SequenceOf");
// Encode to bytes
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&seq).expect("Failed to encode");
encoder.finish().expect("Failed to finish encoding")
}
fn run_benchmark(
name: &str,
data: &[u8],
iterations: usize,
parse_fn: impl Fn(&[u8]) -> Result<usize, Box<dyn std::error::Error>>,
) -> std::time::Duration {
let start = std::time::Instant::now();
for _ in 0..iterations {
let _ = black_box(parse_fn(black_box(data)));
}
let elapsed = start.elapsed();
let per_iter = elapsed / iterations as u32;
println!(" {:<30} {:>12?} ({:>10?} total)", name, per_iter, elapsed);
elapsed
}
fn main() {
println!("SequenceOf vs Element Benchmark\n");
println!("This compares lazy SequenceOf iteration vs eager Element parsing");
println!("for SEQUENCE OF Integer structures.\n");
const ITERATIONS: usize = 100_000;
// Test with different sizes
let test_sizes = vec![5, 10, 20, 50];
for size in test_sizes {
println!("=== Test: SEQUENCE OF with {} Integer elements ===", size);
let data = create_test_data(size);
println!("Encoded size: {} bytes", data.len());
println!("Running {} iterations per method:\n", ITERATIONS);
// Benchmark Element (eager)
let element_time =
run_benchmark("Element (eager Vec)", &data, ITERATIONS, parse_with_element);
// Benchmark SequenceOf lazy iteration
let sequenceof_time = run_benchmark(
"SequenceOf (lazy iteration)",
&data,
ITERATIONS,
parse_with_sequenceof,
);
// Benchmark SequenceOf with collection
let sequenceof_collect_time = run_benchmark(
"SequenceOf + collect_vec",
&data,
ITERATIONS,
parse_with_sequenceof_collect,
);
// Calculate improvements
let lazy_improvement = ((element_time.as_nanos() as f64
- sequenceof_time.as_nanos() as f64)
/ element_time.as_nanos() as f64)
* 100.0;
let collect_improvement = ((element_time.as_nanos() as f64
- sequenceof_collect_time.as_nanos() as f64)
/ element_time.as_nanos() as f64)
* 100.0;
println!("\n Results:");
println!(
" Lazy iteration: {:>6.1}% {} than Element",
lazy_improvement.abs(),
if lazy_improvement > 0.0 {
"faster"
} else {
"slower"
}
);
println!(
" With collect: {:>6.1}% {} than Element",
collect_improvement.abs(),
if collect_improvement > 0.0 {
"faster"
} else {
"slower"
}
);
println!();
}
println!("\n=== Summary ===");
println!("SequenceOf lazy iteration shows the performance benefit when:");
println!(" - You iterate once without collecting");
println!(" - You only need some elements (early termination)");
println!(" - You want zero allocation on parse");
println!("\nElement is better when:");
println!(" - You need random access to elements");
println!(" - You iterate multiple times");
println!(" - Element size is very small");
}
```