pack-io 0.9.0

Compact binary wire format with schema evolution and zero-copy deserialization for Rust. The serialization substrate under network-protocol and Hive DB.
Documentation
<h1 align="center">
    <img width="99" alt="Rust logo" src="https://raw.githubusercontent.com/jamesgober/rust-collection/72baabd71f00e14aa9184efcb16fa3deddda3a0a/assets/rust-logo.svg">
    <br><b>pack-io</b><br>
    <sub><sup>v1.0 PERFORMANCE BASELINE</sup></sub>
</h1>
<div align="center">
    <sup>
        <a href="../README.md" title="Project Home"><b>HOME</b></a>
        <span>&nbsp;&nbsp;</span>
        <a href="../CHANGELOG.md" title="Changelog"><b>CHANGELOG</b></a>
        <span>&nbsp;&nbsp;</span>
        <a href="./API.md" title="API Reference"><b>API</b></a>
        <span>&nbsp;&nbsp;</span>
        <a href="./WIRE_FORMAT.md" title="Wire Format Spec"><b>WIRE FORMAT</b></a>
        <span>&nbsp;&nbsp;</span>
        <a href="./PERFORMANCE.md" title="Performance overview"><b>PERFORMANCE</b></a>
        <span>&nbsp;&nbsp;</span>
        <span>BASELINE</span>
    </sup>
</div>
<br>

> **Frozen baseline captured at v0.9.0** (beta). High-fidelity Criterion
> medians, 100 samples per benchmark, 10 s measurement window per sample,
> 2 s warmup. These are the numbers v1.0 will ship and that downstream
> CI / regression checks should diff against. Any post-1.0 change that
> exceeds a 5 % regression on any row here is treated as a defect per
> [`REPS.md`]../REPS.md.
>
> [`docs/PERFORMANCE.md`]./PERFORMANCE.md carries the full per-row
> analysis, methodology notes, and discussion of intentional losses;
> this file is the frozen data table.

## Environment

| Property                | Value                                                                 |
|-------------------------|-----------------------------------------------------------------------|
| OS                      | Windows 11 Pro 10.0.26200 (x86_64)                                    |
| Toolchain               | Rust stable 1.95.x                                                    |
| Build profile           | `release` (`opt-level = 3, lto = "fat", codegen-units = 1, panic = "abort", strip = "symbols"`) |
| Criterion samples       | 100                                                                   |
| Measurement time        | 10.000 s per sample                                                   |
| Warmup time             | 2.000 s                                                               |
| pack-io version         | 0.9.0 (codec unchanged since v0.6.0)                                  |
| bincode                 | 2.0.1, `config::standard()` (varint)                                  |
| postcard                | 1.x, `to_allocvec` / `from_bytes`                                     |
| rkyv                    | 0.8.16, `to_bytes` + `access::<ArchivedT>` + `deserialize`            |

Reproduce locally:

```bash
cargo bench --bench comparative --features derive -- \
    --warm-up-time 2 --measurement-time 10
```

## Baseline numbers

### Owned-decode of a borrow-heavy log record

Payload: `{ timestamp: u64, level: u8, message: String, tags: Vec<String>, payload: Vec<u8 × 256> }`.

| Codec | Encode | Decode (owned) | Decode (zero-copy) |
|---|---:|---:|---:|
| **pack-io** | **37.9 ns** | 158.9 ns | 34.7 ns |
| bincode | 39.4 ns | **165.1 ns** ||
| postcard | 232.6 ns | 285.1 ns ||
| rkyv | 112.6 ns | 154.6 ns | **12.0 ns** |

### Primitive round-trips

| Workload | pack-io | bincode | postcard |
|---|---:|---:|---:|
| `u64` encode + decode | 22.3 ns | **20.6 ns** ||
| 64-byte `String` (owning) | **44.7 ns** | 48.8 ns ||
| 64-byte `&str` (view) | **5.2 ns** | n/a | n/a |
| 4 KiB `Vec<u8>` decode | **59.7 ns** | 63.0 ns ||

## Summary

- **Wins** *(pack-io fastest of the four)*: encode struct, owning
  `String` round-trip, zero-copy `&str` view, `Vec<u8>` 4 KiB decode.
- **Tied or near-tied** *(within 8 %)*: `u64` round-trip (bincode 1.08×
  faster), owned struct decode (rkyv 1.03× faster, pack-io ahead of
  bincode).
- **Intentional loss**: `decode_view` vs rkyv archived (~3× — rkyv reads
  a raw memory layout; pack-io walks varints by the wire-format spec).

The v0.6 release notes claimed the same picture from a 3 s measurement
window. The 10 s window confirms it with tighter confidence intervals;
no per-row median moves more than ~3 % vs the v0.6 quick-run numbers.

## Regression policy

Per [`REPS.md`](../REPS.md) §Performance:

- A change touching any of the codec hot paths MUST run this benchmark
  and record results.
- A regression exceeding **5 % on any row above** blocks the merge.
- A win exceeding **5 %** on any row updates this file and the CHANGELOG.

The CI matrix does **not** run this benchmark — measurement variance
across CI runners is too high to be useful as a regression gate.
Performance regression checks happen on dedicated hardware between
releases.

---

<sub>Copyright &copy; 2026 <strong>James Gober</strong>. All rights reserved.</sub>