xocomil 0.3.0

A lightweight, zero-allocation HTTP/1.1 request parser and response writer
Documentation
//! Heap-allocation audit for `xocomil::pct`.
//!
//! Run with: `cargo test --release --features dhat-heap --test alloc_pct`
//!
//! Asserts that the percent-decode hot paths perform zero **additional**
//! heap allocations over the test runner's own startup cost. A delta is
//! measured around just the API loop because the Rust test harness
//! itself allocates before the profiler quiesces.
//!
//! One `#[test]` per file (multiple `Profiler` instances per process
//! are unsupported) — sibling files cover query, media, and `BodyReader`.

#![cfg(feature = "dhat-heap")]

use std::hint::black_box;

use xocomil::pct::{self, Mode};

#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;

#[test]
fn pct_hot_paths_zero_alloc() {
    let _profiler = dhat::Profiler::builder().testing().build();

    // Capture baseline *after* the profiler is up so any test-runner
    // setup allocations don't get attributed to the API.
    let baseline = dhat::HeapStats::get();

    // -- Clean path: zero-copy fast path --------------------------------
    let clean = b"/api/v1/users/12345/orders";
    let mut out = [0u8; 64];
    for _ in 0..1000 {
        let r = pct::decode(black_box(clean), Mode::Path, &mut out).unwrap();
        black_box(r);
    }

    // -- Path with escapes ----------------------------------------------
    let with_escapes = b"/users/foo%20bar/items/baz%2Fqux";
    for _ in 0..1000 {
        let r = pct::decode(black_box(with_escapes), Mode::Path, &mut out).unwrap();
        black_box(r);
    }

    // -- Form mode (decodes `+`) ----------------------------------------
    let form = b"hello+world%21+from+rust";
    for _ in 0..1000 {
        let r = pct::decode(black_box(form), Mode::Form, &mut out).unwrap();
        black_box(r);
    }

    let stats = dhat::HeapStats::get();
    dhat::assert_eq!(stats.total_blocks - baseline.total_blocks, 0);
    dhat::assert_eq!(stats.total_bytes - baseline.total_bytes, 0);
}