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
42
43
44    fn pop(&mut self) -> Option<u64> {
45        if self.state.len == 0 {
46            None
47        } else {
48            let val = self.buf[self.state.tail];
49            self.state.tail = (self.state.tail + 1) % N;
50            self.state.len -= 1;
51            Some(val)
52        }
53    }
54
55    fn push(&mut self, val: u64) -> Result<(), &'static str> {
56        if self.is_full() {
57            return Err("RingBuffer overflow: push attempted while full");
58        }
59        self.buf[self.state.head] = val;
60        self.state.head = (self.state.head + 1) % N;
61        self.state.len += 1;
62        Ok(())
63    }
64    fn is_empty(&self) -> bool {
65        self.state.len == 0
66    }
67
68    fn is_full(&self) -> bool {
69        self.state.len == N
70    }
71
72    fn capacity(&self) -> usize {
73        N
74    }
75}
76
77pub enum RingBuffer {
78    Mini(RingInner<MINI_SIZE>),
79    Medium(RingInner<MEDIUM_SIZE>),
80    Large(RingInner<LARGE_SIZE>),
81    StorlekEnorm(RingInner<STORLEK_ENORM>),
82}
83
84pub trait ChunkQueue {
85    fn pop(&mut self) -> Option<u64>;
86    fn push(&mut self, val: u64) -> Result<(), &'static str>;
87    fn is_empty(&self) -> bool;
88    fn is_full(&self) -> bool;
89    fn capacity(&self) -> usize;
90}
91
92impl RingBuffer {
93    pub fn new(max_chunks: usize) -> Self {
94        if max_chunks <= MINI_SIZE {
95            RingBuffer::Mini(RingInner::new())
96        } else if max_chunks <= MEDIUM_SIZE {
97            RingBuffer::Medium(RingInner::new())
98        } else if max_chunks <= LARGE_SIZE {
99            RingBuffer::Large(RingInner::new())
100        } else {
101            RingBuffer::StorlekEnorm(RingInner::new())
102        }
103    }
104}
105
106impl ChunkQueue for RingBuffer {
107    fn pop(&mut self) -> Option<u64> {
108        match self {
109            RingBuffer::Mini(inner) => inner.pop(),
110            RingBuffer::Medium(inner) => inner.pop(),
111            RingBuffer::Large(inner) => inner.pop(),
112            RingBuffer::StorlekEnorm(inner) => inner.pop(),
113        }
114    }
115
116    fn push(&mut self, val: u64) -> Result<(), &'static str> {
117        match self {
118            RingBuffer::Mini(inner) => inner.push(val),
119            RingBuffer::Medium(inner) => inner.push(val),
120            RingBuffer::Large(inner) => inner.push(val),
121            RingBuffer::StorlekEnorm(inner) => inner.push(val),
122        }
123    }
124
125    fn is_empty(&self) -> bool {
126        match self {
127            RingBuffer::Mini(inner) => inner.is_empty(),
128            RingBuffer::Medium(inner) => inner.is_empty(),
129            RingBuffer::Large(inner) => inner.is_empty(),
130            RingBuffer::StorlekEnorm(inner) => inner.is_empty(),
131        }
132    }
133
134    fn is_full(&self) -> bool {
135        match self {
136            RingBuffer::Mini(inner) => inner.is_full(),
137            RingBuffer::Medium(inner) => inner.is_full(),
138            RingBuffer::Large(inner) => inner.is_full(),
139            RingBuffer::StorlekEnorm(inner) => inner.is_full(),
140        }
141    }
142
143    fn capacity(&self) -> usize {
144        match self {
145            RingBuffer::Mini(inner) => inner.capacity(),
146            RingBuffer::Medium(inner) => inner.capacity(),
147            RingBuffer::Large(inner) => inner.capacity(),
148            RingBuffer::StorlekEnorm(inner) => inner.capacity(),
149        }
150    }
151}