# heapster
Single-crate Rust library. Lightweight `no_std` wrapper over any `GlobalAlloc` using relaxed atomics.
## Commands
```sh
# NOTE: tests share the global allocator's process-wide counters and reset
# them, so they MUST run single-threaded (`-- --test-threads 1`); parallel
# runs are flaky.
cargo test -- --test-threads 1 # all tests (default features)
cargo test --features full -- --test-threads 1 # + random_allocs integration test
cargo test --features histograms -- --test-threads 1 # histogram-specific tests
cargo bench # divan benchmarks (custom harness)
cargo clippy --all-targets # clippy::all is deny'd in lib.rs
cargo doc --no-deps --all-features # docs.rs-style docs
```
## Architecture
- `src/lib.rs` — `Heapster<A: GlobalAlloc>` struct, `#[global_allocator]` entrypoint
- `src/stats.rs` — `Stats` struct, `measure()` snapshot diff via `Sub`
- `src/histogram.rs` — `Histogram` (64 power-of-two buckets `[2^k, 2^(k+1))`)
- `src/fmt.rs` — `Display` impls, gated behind `fmt` feature
- Global statics are `#[repr(align(64))]` cache-aligned; all atomics use `Ordering::Relaxed`
- Atomics come from `portable-atomic` (zero-cost on targets with native 64-bit atomics, fallback elsewhere); counts and sums are `u64`, heap-use gauges are `usize`
- Default features = none (minimal production footprint). Features: `histograms`, `use_curr`, `use_max` (implies `use_curr`), `realloc_moves`, `fmt`, `serde`, `full`
## Conventions
- `#![no_std]` by default; `fmt` and `serde` pull in `std`
- `#![deny(missing_docs)]` — every public item must be documented
- `#![deny(clippy::all)]` — clippy warnings are hard errors
- Edition 2024, MSRV 1.85
- `Stats` subtraction uses `saturating_sub` (never panics)
- Tests use a shared `#[global_allocator] static GLOBAL: Heapster<System>` and must run with `--test-threads 1` (CI does)
- Integration test `random_allocs` is `#[cfg(feature = "full")]` and depends on `rand`
- `Cargo.lock` is gitignored (per `.gitignore`)
- Dual-licensed CC0 / MIT