znippy_common/
int_ring.rs

1//! Reusable RingBuffer enum with fixed array backing and trait implementation
2//! Reusable RingBuffer enum with fixed array backing and trait implementation
3//!
4//! Memory usage is estimated assuming 10MB per chunk.
5//! Each thread gets its own RingBuffer. Total memory = SIZE × 10MB × NUM_THREADS (e.g. 32).
6//! The total RAM consumption per size tier (for 32 threads) is approximately:
7//
8//! MINI_SIZE:         4    × 10MB × 32 ≈   1.25 GB
9//! MEDIUM_SIZE:      32    × 10MB × 32 ≈  10.00 GB
10//! LARGE_SIZE:      128    × 10MB × 32 ≈  40.00 GB
11//! STORLEK_ENORM:  8192    × 10MB × 32 ≈ 2560.00 GB (~2.5 TB)
12
13pub const MINI_SIZE: usize = 4; // ~1.25GB total at 10MB per chunk × 32 threads
14pub const MEDIUM_SIZE: usize = 32; // ~10.00GB total
15pub const LARGE_SIZE: usize = 128; // ~40.00GB total
16pub const STORLEK_ENORM: usize = 8192; // ~2.5TB total
17struct RingState {
18    head: usize,
19    tail: usize,
20    len: usize,
21}
22
23struct RingInner<const N: usize> {
24    buf: Box<[u64; N]>,
25    state: RingState,
26}
27
28impl<const N: usize> RingInner<N> {
29    fn new() -> Self {
30        let array = Box::new([0u64; N]);
31        Self {
32            buf: array,
33            state: RingState {
34                head: 0,
35                tail: 0,
36                len: 0, // Börja helt tom
37            },
38        }
39    }
40
41    fn pop(&mut self) -> Option<u64> {
42        if self.state.len == 0 {
43            None
44        } else {
45            let val = self.buf[self.state.tail];
46            self.state.tail = (self.state.tail + 1) % N;
47            self.state.len -= 1;
48            Some(val)
49        }
50    }
51
52    fn push(&mut self, val: u64) -> Result<(), &'static str> {
53        if self.is_full() {
54            return Err("RingBuffer overflow: push attempted while full");
55        }
56        self.buf[self.state.head] = val;
57        self.state.head = (self.state.head + 1) % N;
58        self.state.len += 1;
59        Ok(())
60    }
61    fn is_empty(&self) -> bool {
62        self.state.len == 0
63    }
64
65    fn is_full(&self) -> bool {
66        self.state.len == N
67    }
68
69    fn capacity(&self) -> usize {
70        N
71    }
72}
73
74pub enum RingBuffer {
75    Mini(RingInner<MINI_SIZE>),
76    Medium(RingInner<MEDIUM_SIZE>),
77    Large(RingInner<LARGE_SIZE>),
78    StorlekEnorm(RingInner<STORLEK_ENORM>),
79}
80
81pub trait ChunkQueue {
82    fn pop(&mut self) -> Option<u64>;
83    fn push(&mut self, val: u64) -> Result<(), &'static str>;
84    fn is_empty(&self) -> bool;
85    fn is_full(&self) -> bool;
86    fn capacity(&self) -> usize;
87}
88
89impl RingBuffer {
90    pub fn new(max_chunks: usize) -> Self {
91        if max_chunks <= MINI_SIZE {
92            RingBuffer::Mini(RingInner::new())
93        } else if max_chunks <= MEDIUM_SIZE {
94            RingBuffer::Medium(RingInner::new())
95        } else if max_chunks <= LARGE_SIZE {
96            RingBuffer::Large(RingInner::new())
97        } else {
98            RingBuffer::StorlekEnorm(RingInner::new())
99        }
100    }
101}
102
103impl ChunkQueue for RingBuffer {
104    fn pop(&mut self) -> Option<u64> {
105        match self {
106            RingBuffer::Mini(inner) => inner.pop(),
107            RingBuffer::Medium(inner) => inner.pop(),
108            RingBuffer::Large(inner) => inner.pop(),
109            RingBuffer::StorlekEnorm(inner) => inner.pop(),
110        }
111    }
112
113    fn push(&mut self, val: u64) -> Result<(), &'static str> {
114        match self {
115            RingBuffer::Mini(inner) => inner.push(val),
116            RingBuffer::Medium(inner) => inner.push(val),
117            RingBuffer::Large(inner) => inner.push(val),
118            RingBuffer::StorlekEnorm(inner) => inner.push(val),
119        }
120    }
121
122    fn is_empty(&self) -> bool {
123        match self {
124            RingBuffer::Mini(inner) => inner.is_empty(),
125            RingBuffer::Medium(inner) => inner.is_empty(),
126            RingBuffer::Large(inner) => inner.is_empty(),
127            RingBuffer::StorlekEnorm(inner) => inner.is_empty(),
128        }
129    }
130
131    fn is_full(&self) -> bool {
132        match self {
133            RingBuffer::Mini(inner) => inner.is_full(),
134            RingBuffer::Medium(inner) => inner.is_full(),
135            RingBuffer::Large(inner) => inner.is_full(),
136            RingBuffer::StorlekEnorm(inner) => inner.is_full(),
137        }
138    }
139
140    fn capacity(&self) -> usize {
141        match self {
142            RingBuffer::Mini(inner) => inner.capacity(),
143            RingBuffer::Medium(inner) => inner.capacity(),
144            RingBuffer::Large(inner) => inner.capacity(),
145            RingBuffer::StorlekEnorm(inner) => inner.capacity(),
146        }
147    }
148}