use core::{fmt, marker::PhantomData};
pub const RING_SIZE: usize = 256;
pub type RingIndex = u8;
pub struct SlidingRing<T: Copy, const DEPTH: u8> {
slots: [T; RING_SIZE],
zero: T,
anchor: RingIndex,
}
impl<T: Copy, const DEPTH: u8> SlidingRing<T, DEPTH> {
pub fn new(zero: T) -> Self {
assert!(DEPTH > 0, "SlidingRing DEPTH must be at least 1");
assert!(
DEPTH as usize <= RING_SIZE,
"SlidingRing DEPTH cannot exceed {}",
RING_SIZE
);
Self {
slots: [zero; RING_SIZE],
zero,
anchor: 0,
}
}
pub const DEPTH: u8 = DEPTH;
#[inline(always)]
const fn depth_usize() -> usize {
DEPTH as usize
}
#[inline(always)]
fn shift_internal(&mut self, delta: i128, keep_new_anchor: bool) {
if delta == 0 {
return;
}
let step = diff_mod_256(delta);
self.anchor = self.anchor.wrapping_add(step);
let depth = Self::depth_usize();
let depth_limit = DEPTH as i128;
if delta >= depth_limit || delta <= -depth_limit {
self.slots.fill(self.zero);
return;
}
let count = if delta > 0 {
delta as usize
} else {
(-delta) as usize
};
debug_assert!(count < depth, "delta {} exceeds window {}", delta, DEPTH);
if delta > 0 {
let keep = depth - count;
let mut idx = self.anchor.wrapping_add(keep as u8);
for _ in 0..count {
self.slots[idx as usize] = self.zero;
idx = idx.wrapping_add(1);
}
} else {
let mut idx = self.anchor;
for i in 0..count {
if keep_new_anchor && i == 0 {
idx = idx.wrapping_add(1);
continue;
}
self.slots[idx as usize] = self.zero;
idx = idx.wrapping_add(1);
}
}
}
#[inline(always)]
pub fn borrow_anchor(&self) -> &T {
&self.slots[self.anchor as usize]
}
#[inline(always)]
pub fn borrow_anchor_mut(&mut self) -> &mut T {
&mut self.slots[self.anchor as usize]
}
#[inline(always)]
pub fn slot(&self, offset: RingIndex) -> &T {
debug_assert!(
(offset as usize) < Self::depth_usize(),
"offset {} is outside the configured depth ({})",
offset,
DEPTH
);
let idx = self.anchor.wrapping_add(offset);
&self.slots[idx as usize]
}
#[inline(always)]
pub fn slot_mut(&mut self, offset: RingIndex) -> &mut T {
debug_assert!(
(offset as usize) < Self::depth_usize(),
"offset {} is outside the configured depth ({})",
offset,
DEPTH
);
let idx = self.anchor.wrapping_add(offset);
&mut self.slots[idx as usize]
}
#[inline(always)]
pub fn shift_by(&mut self, delta: i128) {
self.shift_internal(delta, false);
}
#[inline(always)]
pub fn shift_by_keep_anchor(&mut self, delta: i128) {
self.shift_internal(delta, true);
}
#[inline(always)]
pub fn slot_by_index(&self, index: RingIndex) -> &T {
&self.slots[index as usize]
}
#[inline(always)]
pub fn slot_by_index_mut(&mut self, index: RingIndex) -> &mut T {
&mut self.slots[index as usize]
}
#[inline(always)]
pub fn clear_all(&mut self) {
self.slots.fill(self.zero);
self.anchor = 0;
}
#[inline(always)]
pub fn as_slice(&self) -> &[T; RING_SIZE] {
&self.slots
}
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [T; RING_SIZE] {
&mut self.slots
}
#[inline(always)]
pub fn slices_from_anchor(&self) -> (&[T], &[T]) {
let start = self.anchor as usize;
let depth = Self::depth_usize();
if depth >= RING_SIZE {
let (head, tail) = self.slots.split_at(start);
return (tail, head);
}
let tail_len = depth.min(RING_SIZE - start);
let head_len = depth - tail_len;
let tail = &self.slots[start..start + tail_len];
let head = &self.slots[..head_len];
(tail, head)
}
#[inline(always)]
pub fn slices_from_anchor_mut(&mut self) -> (&mut [T], &mut [T]) {
let start = self.anchor as usize;
let depth = Self::depth_usize();
if depth >= RING_SIZE {
let (head, tail) = self.slots.split_at_mut(start);
return (tail, head);
}
let tail_len = depth.min(RING_SIZE - start);
let head_len = depth - tail_len;
let (head, tail) = self.slots.split_at_mut(start);
let (tail_window, _) = tail.split_at_mut(tail_len);
let head_window = &mut head[..head_len];
(tail_window, head_window)
}
#[inline(always)]
pub fn iter(&self) -> Slots<'_, T> {
Slots::new(&self.slots)
}
#[inline(always)]
pub fn iter_mut(&mut self) -> SlotsMut<'_, T> {
SlotsMut::new(&mut self.slots)
}
#[inline(always)]
pub fn iter_from_anchor(&self, direction: Direction) -> AnchorIter<'_, T, DEPTH> {
AnchorIter::new(self, direction)
}
#[inline(always)]
pub fn iter_from_anchor_mut(&mut self, direction: Direction) -> AnchorIterMut<'_, T, DEPTH> {
AnchorIterMut::new(self, direction)
}
}
impl<T: Copy, const DEPTH: u8> fmt::Debug for SlidingRing<T, DEPTH> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SlidingRing")
.field("anchor_index", &self.anchor)
.finish()
}
}
#[derive(Copy, Clone, Debug)]
pub enum Direction {
Forward,
Backward,
}
pub struct Slots<'a, T> {
ptr: *const T,
end: *const T,
_marker: PhantomData<&'a T>,
}
impl<'a, T> Slots<'a, T> {
#[inline(always)]
fn new(slice: &'a [T; RING_SIZE]) -> Self {
let ptr = slice.as_ptr();
unsafe {
Self {
ptr,
end: ptr.add(RING_SIZE),
_marker: PhantomData,
}
}
}
}
impl<'a, T> Iterator for Slots<'a, T> {
type Item = &'a T;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
return None;
}
unsafe {
let item = &*self.ptr;
self.ptr = self.ptr.add(1);
Some(item)
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = unsafe { self.end.offset_from(self.ptr) as usize };
(len, Some(len))
}
}
impl<'a, T> ExactSizeIterator for Slots<'a, T> {
#[inline(always)]
fn len(&self) -> usize {
unsafe { self.end.offset_from(self.ptr) as usize }
}
}
impl<'a, T> core::iter::FusedIterator for Slots<'a, T> {}
pub struct SlotsMut<'a, T> {
ptr: *mut T,
end: *mut T,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T> SlotsMut<'a, T> {
#[inline(always)]
fn new(slice: &'a mut [T; RING_SIZE]) -> Self {
let ptr = slice.as_mut_ptr();
unsafe {
Self {
ptr,
end: ptr.add(RING_SIZE),
_marker: PhantomData,
}
}
}
}
impl<'a, T> Iterator for SlotsMut<'a, T> {
type Item = &'a mut T;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
return None;
}
unsafe {
let item = &mut *self.ptr;
self.ptr = self.ptr.add(1);
Some(item)
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = unsafe { self.end.offset_from(self.ptr) as usize };
(len, Some(len))
}
}
impl<'a, T> ExactSizeIterator for SlotsMut<'a, T> {
#[inline(always)]
fn len(&self) -> usize {
unsafe { self.end.offset_from(self.ptr) as usize }
}
}
impl<'a, T> core::iter::FusedIterator for SlotsMut<'a, T> {}
pub struct AnchorIter<'a, T: Copy, const DEPTH: u8> {
ptr: *const T,
base: *const T,
end: *const T,
remaining: usize,
offset: i16,
direction: Direction,
_marker: PhantomData<&'a T>,
}
impl<'a, T: Copy, const DEPTH: u8> AnchorIter<'a, T, DEPTH> {
#[inline(always)]
fn new(ring: &'a SlidingRing<T, DEPTH>, direction: Direction) -> Self {
let base = ring.slots.as_ptr();
let ptr = unsafe { base.add(ring.anchor as usize) };
let end = unsafe { base.add(RING_SIZE) };
Self {
ptr,
base,
end,
remaining: SlidingRing::<T, DEPTH>::depth_usize(),
offset: 0,
direction,
_marker: PhantomData,
}
}
}
impl<'a, T: Copy, const DEPTH: u8> Iterator for AnchorIter<'a, T, DEPTH> {
type Item = (i16, &'a T);
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
unsafe {
let item = &*self.ptr;
self.ptr = match self.direction {
Direction::Forward => {
let next = self.ptr.add(1);
if next == self.end { self.base } else { next }
}
Direction::Backward => {
if self.ptr == self.base {
self.end.sub(1)
} else {
self.ptr.sub(1)
}
}
};
let coord = self.offset;
match self.direction {
Direction::Forward => self.offset = self.offset.wrapping_add(1),
Direction::Backward => self.offset = self.offset.wrapping_sub(1),
}
Some((coord, item))
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<'a, T: Copy, const DEPTH: u8> ExactSizeIterator for AnchorIter<'a, T, DEPTH> {
#[inline(always)]
fn len(&self) -> usize {
self.remaining
}
}
impl<'a, T: Copy, const DEPTH: u8> core::iter::FusedIterator for AnchorIter<'a, T, DEPTH> {}
pub struct AnchorIterMut<'a, T: Copy, const DEPTH: u8> {
ptr: *mut T,
base: *mut T,
end: *mut T,
remaining: usize,
offset: i16,
direction: Direction,
_marker: PhantomData<&'a mut T>,
}
impl<'a, T: Copy, const DEPTH: u8> AnchorIterMut<'a, T, DEPTH> {
#[inline(always)]
fn new(ring: &'a mut SlidingRing<T, DEPTH>, direction: Direction) -> Self {
let base = ring.slots.as_mut_ptr();
let ptr = unsafe { base.add(ring.anchor as usize) };
let end = unsafe { base.add(RING_SIZE) };
Self {
ptr,
base,
end,
remaining: SlidingRing::<T, DEPTH>::depth_usize(),
offset: 0,
direction,
_marker: PhantomData,
}
}
}
impl<'a, T: Copy, const DEPTH: u8> Iterator for AnchorIterMut<'a, T, DEPTH> {
type Item = (i16, &'a mut T);
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
unsafe {
let item = &mut *self.ptr;
self.ptr = match self.direction {
Direction::Forward => {
let next = self.ptr.add(1);
if next == self.end { self.base } else { next }
}
Direction::Backward => {
if self.ptr == self.base {
self.end.sub(1)
} else {
self.ptr.sub(1)
}
}
};
let coord = self.offset;
match self.direction {
Direction::Forward => self.offset = self.offset.wrapping_add(1),
Direction::Backward => self.offset = self.offset.wrapping_sub(1),
}
Some((coord, item))
}
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<'a, T: Copy, const DEPTH: u8> ExactSizeIterator for AnchorIterMut<'a, T, DEPTH> {
#[inline(always)]
fn len(&self) -> usize {
self.remaining
}
}
impl<'a, T: Copy, const DEPTH: u8> core::iter::FusedIterator for AnchorIterMut<'a, T, DEPTH> {}
#[inline]
pub fn diff_mod_256(diff: i128) -> RingIndex {
(diff & 255) as RingIndex
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_DEPTH: u8 = 64;
#[test]
fn diff_mod_matches_reference() {
let xs = [
i128::MIN,
i128::MIN / 2,
-65_536,
-10_000,
-1024,
-256,
-255,
-1,
0,
1,
127,
254,
255,
256,
1024,
10_000,
65_536,
i128::MAX / 2,
i128::MAX,
];
for &d in &xs {
let m = diff_mod_256(d);
let expected = (d.rem_euclid(256)) as u8;
assert_eq!(m, expected);
}
}
#[test]
fn slot_reads_and_writes_by_offset() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
*ring.borrow_anchor_mut() = 5;
*ring.slot_mut(1) = 7;
assert_eq!(*ring.borrow_anchor(), 5);
assert_eq!(*ring.slot(1), 7);
}
#[test]
fn shift_by_forward_clears_tail() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
for off in 0..TEST_DEPTH {
*ring.slot_mut(off) = 1;
}
ring.shift_by(5);
let depth = TEST_DEPTH as usize;
for off in 0..(depth - 5) {
assert_eq!(*ring.slot(off as RingIndex), 1);
}
for off in depth - 5..depth {
assert_eq!(*ring.slot(off as RingIndex), 0);
}
}
#[test]
fn shift_by_backward_clears_head() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
for off in 0..TEST_DEPTH {
*ring.slot_mut(off) = 1;
}
ring.shift_by(-4);
for off in 0..4 {
assert_eq!(*ring.slot(off as RingIndex), 0);
}
for off in 4..TEST_DEPTH as usize {
assert_eq!(*ring.slot(off as RingIndex), 1);
}
}
#[test]
fn shift_by_large_distance_resets_all() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
for off in 0..TEST_DEPTH {
*ring.slot_mut(off) = 9;
}
ring.shift_by(TEST_DEPTH as i128);
for off in 0..TEST_DEPTH {
assert_eq!(*ring.slot(off), 0);
}
}
#[test]
fn shift_by_keep_anchor_preserves_anchor_slot() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
let head0 = diff_mod_256(-1);
let head1 = diff_mod_256(-2);
let head2 = diff_mod_256(-3);
*ring.slot_by_index_mut(head0) = 11;
*ring.slot_by_index_mut(head1) = 22;
*ring.slot_by_index_mut(head2) = 33;
ring.shift_by_keep_anchor(-3);
assert_eq!(*ring.borrow_anchor(), 33);
assert_eq!(*ring.slot(1), 0);
assert_eq!(*ring.slot(2), 0);
}
#[test]
fn iterators_cover_all_slots_in_storage_order() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
for (i, slot) in ring.iter_mut().enumerate() {
*slot = i as u64;
}
for (i, slot) in ring.iter().enumerate() {
assert_eq!(*slot, i as u64);
}
}
#[test]
fn slices_from_anchor_split_correctly() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
for (i, slot) in ring.iter_mut().enumerate() {
*slot = i as u64;
}
ring.shift_by(100);
*ring.borrow_anchor_mut() = u64::MAX;
let (tail, head) = ring.slices_from_anchor();
let window = TEST_DEPTH as usize;
let anchor_idx = ring
.as_slice()
.iter()
.position(|&v| v == u64::MAX)
.expect("sentinel present");
let expected_tail = window.min(RING_SIZE - anchor_idx);
assert_eq!(head.len() + tail.len(), window);
assert_eq!(tail.len(), expected_tail);
assert_eq!(head.len(), window - expected_tail);
}
#[test]
fn anchor_iter_traverses_forward() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
ring.shift_by(50);
for (i, slot) in ring.iter_mut().enumerate() {
*slot = i as u64;
}
let mut offsets = Vec::new();
for (offset, _) in ring.iter_from_anchor(Direction::Forward).take(3) {
offsets.push(offset);
}
assert_eq!(offsets, vec![0, 1, 2]);
}
#[test]
fn anchor_iter_traverses_backward() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
ring.shift_by(50);
let mut offsets = Vec::new();
for (offset, _) in ring.iter_from_anchor(Direction::Backward).take(3) {
offsets.push(offset);
}
assert_eq!(offsets, vec![0, -1, -2]);
}
#[test]
fn option_slots_clear_back_to_none() {
let mut ring = SlidingRing::<Option<u32>, TEST_DEPTH>::new(None);
*ring.slot_mut(5) = Some(42);
ring.shift_by(TEST_DEPTH as i128);
for off in 0..TEST_DEPTH {
assert!(ring.slot(off).is_none());
}
}
#[test]
fn custom_copy_slots_reset_to_zero() {
#[derive(Clone, Copy)]
struct Level {
qty: u32,
}
let mut ring = SlidingRing::<Level, TEST_DEPTH>::new(Level { qty: 0 });
ring.slot_mut(3).qty = 7;
ring.shift_by(TEST_DEPTH as i128);
assert_eq!(ring.slot(3).qty, 0);
}
#[test]
fn anchor_index_wraps_modulo() {
let mut ring = SlidingRing::<u64, TEST_DEPTH>::new(0);
let diff = i128::MAX - 100;
ring.shift_by(diff);
*ring.borrow_anchor_mut() = 7;
let idx = ring
.as_slice()
.iter()
.position(|&v| v == 7)
.expect("sentinel should be present");
assert_eq!(idx as u8, diff_mod_256(diff));
}
}