Expand description
Fixed-size sliding ring buffer with anchor-preserving index math.
SlidingRing keeps a circular array of 256 slots whose live window begins at an
anchor index. Moves are expressed as signed deltas; the ring rewires indices in
constant time and zeroes only the slots that newly enter the window (or the entire
ring when the delta exceeds the configured depth). Any domain-specific “anchor
coordinate” should be stored outside the ring and combined with offsets as needed.
§Model overview
- The ring tracks an anchor index (0-255). Store your absolute coordinate outside the ring.
- Moving by
kadjusts the anchor index byk mod 256and clears exactly|k|freshly entered offsets (full reset when|k| >= DEPTH). SlidingRing::slot/SlidingRing::slot_mutaccept offsets relative to the anchor, keeping lookups branch-free.SlidingRing::shift_by_keep_anchorpreserves the newly entered anchor slot on backward moves so consumers can promote “next best” levels without losing their quantity.
§When to use it
Use this crate any time you need a cache-friendly sliding window tied to a monotonically moving reference point and you can tolerate a fixed resolution of 256 discrete offsets. Typical use-cases include:
- Aggregated orderbooks keyed by price ticks.
- Sliding time buckets for telemetry or rate-limiters.
- Game state timelines (e.g., ringed entity positions) where only a bounded horizon surrounding the current tick matters.
§When not to use it
- You need more than 256 distinct offsets at a time.
- The anchor jumps arbitrarily with sparse occupancy (use a hashmap instead).
- Slots require heap allocations on clear (prefer a structure that owns the heap nodes elsewhere and references them by ID).
§Slot requirements
The buffer stores [T; 256] where T: Copy. Pass the value that represents
your cleared state (often zero) to SlidingRing::new; the ring seeds every
slot with that value and reuses it whenever newly entered slots need to be
cleared. This keeps the API simple and removes the need for a custom trait.
For ultra-low latency users, the main primitive is
SlidingRing::slices_from_anchor, which returns the two contiguous spans
that cover the ring starting at the anchor. Operate on those slices directly
with SIMD or unrolled loops when you need raw throughput. The iterator
variants (iter*) simply layer offset reporting on top of the
same index arithmetic and remain zero-cost.
Pair those slices with a stable SIMD helper (e.g., the wide
crate demonstrated in examples/simd_scan.rs) to keep portable performance on stable Rust.
§Example
use sliding_ring::SlidingRing;
#[derive(Debug, Copy, Clone)]
struct Level { qty: u64 }
const DEPTH: u8 = 64;
let mut ring = SlidingRing::<Level, DEPTH>::new(Level { qty: 0 });
let mut best = 1_000i128;
let offset = 5u8;
ring.slot_mut(offset).qty = 10;
ring.shift_by(offset as i128);
best += offset as i128;
assert_eq!(ring.borrow_anchor().qty, 10);§Telemetry counter example
#[derive(Clone, Copy)]
struct Bucket { hits: u64 }
const DEPTH: u8 = 32;
let mut ring = SlidingRing::<Bucket, DEPTH>::new(Bucket { hits: 0 });
ring.slot_mut(5).hits += 1;
ring.slot_mut(6).hits += 3;
let sum: u64 = ring
.iter_from_anchor(Direction::Forward)
.map(|(_, bucket)| bucket.hits)
.sum();
assert_eq!(sum, 4);Structs§
- Anchor
Iter - Anchor-ordered iterator (immutable).
- Anchor
Iter Mut - Anchor-ordered iterator (mutable).
- Sliding
Ring - Ring that slides over signed coordinates while keeping slot access O(1).
- Slots
- Raw-pointer iterator over an immutable ring slice.
- Slots
Mut - Raw-pointer iterator over a mutable ring slice.
Enums§
- Direction
- Iteration order relative to the anchor.
Constants§
- RING_
SIZE - Number of slots in the ring.
Functions§
- diff_
mod_ 256 - Reduce a signed difference mod 256 (ring size).