synta 0.1.6

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# 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");
}
```