Crate sliding_ring

Crate sliding_ring 

Source
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 k adjusts the anchor index by k mod 256 and clears exactly |k| freshly entered offsets (full reset when |k| >= DEPTH).
  • SlidingRing::slot / SlidingRing::slot_mut accept offsets relative to the anchor, keeping lookups branch-free.
  • SlidingRing::shift_by_keep_anchor preserves 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§

AnchorIter
Anchor-ordered iterator (immutable).
AnchorIterMut
Anchor-ordered iterator (mutable).
SlidingRing
Ring that slides over signed coordinates while keeping slot access O(1).
Slots
Raw-pointer iterator over an immutable ring slice.
SlotsMut
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).

Type Aliases§

RingIndex