Skip to main content

radiate_utils/buff/
window.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use std::fmt::Debug;
4
5#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6pub struct WindowBuffer<T> {
7    buffer: Vec<T>,
8    cap: usize,
9    max: usize,
10    start: usize,
11    end: usize,
12}
13
14impl<T> WindowBuffer<T> {
15    pub fn with_capacity(cap: usize) -> Self {
16        debug_assert!(cap > 0, "WindowBuffer capacity must be > 0");
17
18        let max = cap * 2;
19        Self {
20            buffer: Vec::with_capacity(max),
21            cap,
22            max,
23            start: 0,
24            end: 0,
25        }
26    }
27
28    #[inline]
29    pub fn push(&mut self, item: T) -> bool {
30        let mut resized = false;
31        // check if the buffer is at capacity
32        if self.buffer.len() >= self.cap {
33            // check if the buffer is full
34            if self.buffer.len() >= self.max {
35                if self.end >= self.max {
36                    let (front, back) = self.buffer.split_at_mut(self.cap);
37                    front.swap_with_slice(back);
38
39                    self.start = 0;
40                    self.end = self.cap;
41                }
42                self.buffer[self.end] = item;
43            } else {
44                self.buffer.push(item);
45            }
46
47            resized = true;
48
49            self.start += 1;
50            self.end += 1;
51        } else {
52            self.buffer.push(item);
53            self.end += 1;
54            if self.end - self.start > self.cap {
55                self.start += 1;
56            }
57        }
58
59        resized
60    }
61
62    pub fn push_front(&mut self, item: T) -> bool {
63        if self.buffer.len() < self.cap {
64            // Buffer isn't full yet.
65            self.buffer.insert(0, item);
66            self.end += 1;
67            return false;
68        }
69
70        if self.buffer.len() < self.max {
71            // Grow toward the front.
72            self.buffer.insert(0, item);
73
74            // Everything shifted right.
75            self.end += 1;
76
77            // Keep only the newest `cap` items.
78            if self.end - self.start > self.cap {
79                self.end -= 1;
80                self.buffer.pop();
81            }
82
83            return true;
84        }
85
86        // Buffer has reached max allocation.
87        if self.start == 0 {
88            // Make room at the front.
89            let (front, back) = self.buffer.split_at_mut(self.cap);
90            front.swap_with_slice(back);
91
92            self.start = self.cap;
93            self.end = self.max;
94        }
95
96        self.start -= 1;
97        self.end -= 1;
98
99        self.buffer[self.start] = item;
100
101        true
102    }
103
104    #[inline]
105    pub fn len(&self) -> usize {
106        self.buffer.len().saturating_sub(self.start)
107    }
108
109    #[inline]
110    pub fn is_empty(&self) -> bool {
111        self.len() == 0
112    }
113
114    #[inline]
115    pub fn values(&self) -> &[T] {
116        &self.buffer[self.start..self.end]
117    }
118
119    pub fn iter(&self) -> impl Iterator<Item = &T> {
120        self.values().iter()
121    }
122
123    pub fn as_slice(&self) -> &[T] {
124        self.values()
125    }
126
127    pub fn clear(&mut self) {
128        self.buffer.clear();
129        self.start = 0;
130        self.end = 0;
131    }
132}
133
134impl<T: Clone> Clone for WindowBuffer<T> {
135    fn clone(&self) -> Self {
136        Self {
137            buffer: self.buffer.clone(),
138            cap: self.cap,
139            max: self.max,
140            start: self.start,
141            end: self.end,
142        }
143    }
144}
145
146impl<T: PartialEq> PartialEq for WindowBuffer<T> {
147    fn eq(&self, other: &Self) -> bool {
148        self.values() == other.values()
149    }
150}
151
152impl<T: Debug> Debug for WindowBuffer<T> {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        f.debug_struct("WindowBuffer")
155            .field("capacity", &self.cap)
156            .field("values", &self.values())
157            .finish()
158    }
159}
160
161// #[cfg(test)]
162// mod tests {
163//     use super::WindowBuffer;
164
165//     #[test]
166//     fn ring_buffer_works() {
167//         let mut buffer = WindowBuffer::with_capacity(5);
168//         for i in 0..20 {
169//             buffer.push_front(i);
170//             println!(
171//                 "Buffer: {:?} - {:?}, {:?}",
172//                 buffer.values(),
173//                 buffer.start,
174//                 buffer.end
175//             );
176//         }
177//     }
178// }