//! `Column` — a fixed-capacity, bounded-lookback SoA ring with financial //! indexing (index 0 = newest), and its zero-copy read view `Window` (C5/C8). /// A fixed-capacity bounded-lookback column. Pre-sized at construction /// (C8: no realloc in the hot loop); index 0 = newest; carries a monotonic /// `run_count` of total pushes — the freshness primitive (C5). pub struct Column { buf: Box<[T]>, head: usize, // next write slot len: usize, // valid elements, saturates at capacity run_count: u64, // monotonic total pushes (C5) } impl Column { /// Create a column sized to `lookback` (must be >= 1). The engine sizes this /// once at wiring; it is never reallocated (C8). pub fn with_capacity(lookback: usize) -> Self { assert!(lookback >= 1, "Column lookback must be >= 1"); Column { buf: vec![T::default(); lookback].into_boxed_slice(), head: 0, len: 0, run_count: 0, } } /// Append the newest value. O(1), allocation-free. On overflow the oldest /// value is overwritten (true ring). Bumps `run_count`. pub fn push(&mut self, v: T) { let cap = self.buf.len(); self.buf[self.head] = v; self.head = (self.head + 1) % cap; if self.len < cap { self.len += 1; } self.run_count += 1; } /// Financial index: 0 = newest, `len()-1` = oldest. `None` if `k >= len` /// (C8: not-yet-warmed-up / out of range). Zero-copy. pub fn get(&self, k: usize) -> Option { if k >= self.len { return None; } let cap = self.buf.len(); Some(self.buf[(self.head + cap - 1 - k) % cap]) } pub fn len(&self) -> usize { self.len } pub fn is_empty(&self) -> bool { self.len == 0 } pub fn capacity(&self) -> usize { self.buf.len() } /// The monotonic push counter — the freshness primitive (C5). Never moved /// by a read. pub fn run_count(&self) -> u64 { self.run_count } /// A zero-copy read view handed to a reading node (C8). pub fn window(&self) -> Window<'_, T> { Window { col: self } } } /// Read-only, zero-copy view into a [`Column`] — what a reading node sees (C8). /// Carries no storage, only a borrow. pub struct Window<'a, T> { col: &'a Column, } impl<'a, T: Copy + Default> Window<'a, T> { /// Financial index, 0 = newest; `None` if cold / out of range. pub fn get(&self, k: usize) -> Option { self.col.get(k) } pub fn len(&self) -> usize { self.col.len() } pub fn is_empty(&self) -> bool { self.col.is_empty() } pub fn run_count(&self) -> u64 { self.col.run_count() } } /// `window[k]` — newest-at-0 indexed access; panics on out-of-range like a /// slice. Nodes that may be cold use [`Window::get`] instead. impl<'a, T: Copy + Default> core::ops::Index for Window<'a, T> { type Output = T; fn index(&self, k: usize) -> &T { let col = self.col; assert!(k < col.len, "Window index {k} out of range (len {})", col.len); let cap = col.buf.len(); &col.buf[(col.head + cap - 1 - k) % cap] } } #[cfg(test)] mod tests { use super::*; #[test] fn newest_at_zero_oldest_at_len_minus_one() { let mut c = Column::::with_capacity(4); c.push(10); c.push(20); c.push(30); assert_eq!(c.len(), 3); assert_eq!(c.get(0), Some(30)); // newest assert_eq!(c.get(1), Some(20)); assert_eq!(c.get(2), Some(10)); // oldest assert_eq!(c.get(3), None); // beyond len } #[test] fn wraparound_keeps_newest_capacity_values() { let mut c = Column::::with_capacity(3); for v in [1, 2, 3, 4, 5] { c.push(v); } assert_eq!(c.len(), 3); // saturated assert_eq!(c.capacity(), 3); assert_eq!(c.get(0), Some(5)); // newest assert_eq!(c.get(1), Some(4)); assert_eq!(c.get(2), Some(3)); // oldest retained assert_eq!(c.get(3), None); // 1 and 2 were dropped } #[test] fn run_count_counts_pushes_not_len() { let mut c = Column::::with_capacity(2); assert_eq!(c.run_count(), 0); for v in [1, 2, 3, 4, 5] { c.push(v); } assert_eq!(c.run_count(), 5); // counts pushes, past the ring wrap assert_eq!(c.len(), 2); // while len stays at capacity let _ = c.get(0); assert_eq!(c.run_count(), 5); // a read never moves it } #[test] fn window_is_a_view_matching_the_column() { let mut c = Column::::with_capacity(4); c.push(1.0); c.push(2.0); let cap_before = c.capacity(); let w = c.window(); assert_eq!(w.len(), 2); assert_eq!(w.get(0), Some(2.0)); assert_eq!(w[1], 1.0); // Index, newest-at-0 assert_eq!(w.run_count(), 2); assert_eq!(c.capacity(), cap_before); // taking a window did not realloc } #[test] fn empty_column_reads_none() { let c = Column::::with_capacity(2); assert!(c.is_empty()); assert_eq!(c.get(0), None); assert_eq!(c.run_count(), 0); } }