mrc 0.3.0

MRC-2014 file format reader/writer for cryo-EM — SIMD-accelerated, mmap-enabled
Documentation
# Update Log

## 2026-07-03 — v0.2.6 → v0.3.0

~5,500 lines changed across 31 files. This release marks the API maturing past the
"add everything" phase: conversion is gated through a single `ConvertReader` rather
than a scatter of per-mode shortcut methods, and the public surface is tidied up
with inherent forwarding.

### Breaking API Changes

| Removed | Replacement |
|---------|-------------|
| `reader.slices_f32()` | `reader.convert::<f32>().slices()` |
| `reader.slabs_f32()` | `reader.convert::<f32>().slabs(k)` |
| `reader.read_volume_f32()` | `reader.convert::<f32>().read_volume()` |
| `slices_f32_body!` macro (internal) | `convert_iter` + `RawRegionIter` |
| `ReaderExt` trait (mid-refactor artifact) | inherent methods via `impl_reader_forwarding!` |

### New Features

- **Unified conversion API** — `ConvertReader` gating all mode conversions through
  a single `.convert::<T>()` entry point, with builder-style configuration for
  complex strategy and M0 interpretation
- **Built-in `ndarray` support** — `reader.to_ndarray::<T>()` returns
  `ndarray::Array3<T>` when the `ndarray` feature is enabled
- **Extended header parsers** — typed parsing for CCP4 symmetry records, MRCO
  legacy records, SerialEM records (with `alpha_tilt` field), and Agard records
- **Inherent forwarding** — all `ReaderMethods` / `ConvertMethods` methods are
  available as inherent methods on `Reader` and `MmapReader`; no trait imports
  needed for normal use
- **SIMD expansion** — added u16→f32, u8→f32, f16↔f32, byte-swap (2/4/8 byte),
  and f32 statistics kernels; all with runtime feature detection
- **Criterion benchmarks** — `benches/bench.rs` covering slices, mmap, write,
  stats, and conversion hot paths
- **Integration test suite** — `tests/integration.rs` with ~21 roundtrip tests
  for all modes, compression, subregion reads, and edge cases

### Refinements

- **`#[cold]` on hot-path error branches** — `cold_bounds_error()` helper in
  `encode_block_to_buf` / `write_block_bytes` hints LLVM to sink error branches
- **Removed `TypeId` + `unsafe` pattern** — `update_running_stats_f32()` eliminated;
  `update_header_stats()` now always reads from disk (Writer), mmap (MmapWriter),
  or in-memory buffer (CompressedWriter). This removes the `std::any::TypeId` trick
  and the `unsafe { core::slice::from_raw_parts }` transmute
- **Added `clippy::perf` to deny** alongside `unwrap_used` and `expect_used`

### Doc Overhaul

- **README.md** — Fixed stale roadmap (CCP4/MRCO/SERI/AGAR were marked undone but
  are implemented). Added extended header parsers to the feature list.
- **AGENTS.md** — Synced dep versions to `Cargo.toml`. Updated clippy reference.
  Bumped test counts (~80→~91 unit, clarified doc-test count).
- **APIs.md** — Added disk-read performance note on `Writer::update_header_stats()`.

### Testing

91 unit tests, 21 integration tests, 33 doc-tests, clippy — all pass cleanly across
debug, release, and --all-features builds.


### References

- MRC2014 Specification: https://www.ccpem.ac.uk/mrc-format/mrc2014/