1use core::mem::MaybeUninit;
8
9#[repr(C)]
12pub struct RingBuffer<T, const N: usize> {
13 data: [MaybeUninit<T>; N],
14
15 head: u32,
17
18 tail: u32,
20
21 size: u32,
23}
24
25zr::static_assert!(core::mem::size_of::<RingBuffer<u8, 10>>() == 24);
27zr::static_assert!(core::mem::align_of::<RingBuffer<u8, 10>>() == 4);
28
29impl<T, const N: usize> RingBuffer<T, N> {
30 const ASSERT_N_POSITIVE: () = assert!(N > 0);
31 const ASSERT_N_FITS_U32: () = assert!(N <= u32::MAX as usize);
32
33 pub const fn new() -> Self {
35 let _ = Self::ASSERT_N_POSITIVE;
36 let _ = Self::ASSERT_N_FITS_U32;
37 RingBuffer { data: [const { MaybeUninit::uninit() }; N], head: 0, tail: 0, size: 0 }
38 }
39
40 pub fn size(&self) -> u32 {
42 self.size
43 }
44
45 pub const fn capacity() -> usize {
47 N
48 }
49
50 pub fn is_empty(&self) -> bool {
52 self.size == 0
53 }
54
55 pub fn is_full(&self) -> bool {
57 self.size == N as u32
58 }
59
60 pub fn front(&self) -> &T {
66 assert!(!self.is_empty(), "Calling front on an empty RingBuffer");
67 unsafe { self.data[self.head as usize].assume_init_ref() }
69 }
70
71 pub fn front_mut(&mut self) -> &mut T {
77 assert!(!self.is_empty(), "Calling front_mut on an empty RingBuffer");
78 unsafe { self.data[self.head as usize].assume_init_mut() }
80 }
81
82 pub fn back(&self) -> &T {
88 assert!(!self.is_empty(), "Calling back on an empty RingBuffer");
89 let index = self.previous(self.tail);
90 unsafe { self.data[index as usize].assume_init_ref() }
92 }
93
94 pub fn back_mut(&mut self) -> &mut T {
100 assert!(!self.is_empty(), "Calling back_mut on an empty RingBuffer");
101 let index = self.previous(self.tail);
102 unsafe { self.data[index as usize].assume_init_mut() }
104 }
105
106 pub fn pop(&mut self) {
112 assert!(!self.is_empty(), "Calling pop on an empty RingBuffer");
113 unsafe { self.data[self.head as usize].assume_init_drop() };
115 self.head = self.next(self.head);
116 self.size -= 1;
117 }
118
119 pub fn push(&mut self, obj: T) {
125 assert!(!self.is_full(), "Calling push on a full RingBuffer");
126 self.data[self.tail as usize].write(obj);
127 self.tail = self.next(self.tail);
128 self.size += 1;
129 }
130
131 pub fn clear(&mut self) {
133 while !self.is_empty() {
134 self.pop();
135 }
136 self.head = 0;
137 self.tail = 0;
138 self.size = 0;
139 }
140
141 fn next(&self, index: u32) -> u32 {
142 if index == (N as u32 - 1) { 0 } else { index + 1 }
143 }
144
145 fn previous(&self, index: u32) -> u32 {
146 if index == 0 { N as u32 - 1 } else { index - 1 }
147 }
148}
149
150impl<T, const N: usize> Drop for RingBuffer<T, N> {
151 fn drop(&mut self) {
152 self.clear();
153 }
154}
155
156impl<T, const N: usize> Default for RingBuffer<T, N> {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use core::sync::atomic::{AtomicU32, Ordering};
166
167 #[test]
168 fn pod_push() {
169 const BUFF_SIZE: usize = 10;
170 let mut buffer = RingBuffer::<u8, BUFF_SIZE>::new();
171 assert_eq!(buffer.size(), 0);
172 assert!(buffer.is_empty());
173
174 for i in 0..BUFF_SIZE {
176 buffer.push(i as u8);
177 assert_eq!(*buffer.front(), 0);
178 assert_eq!(*buffer.back(), i as u8);
179 }
180
181 assert!(buffer.is_full());
182 assert_eq!(*buffer.front(), 0);
183
184 for i in 0..BUFF_SIZE {
185 assert_eq!(*buffer.front(), i as u8);
186 assert_eq!(*buffer.back(), (BUFF_SIZE - 1) as u8);
187 buffer.pop();
188 }
189
190 assert!(buffer.is_empty());
191
192 buffer.push(11);
194 assert_eq!(*buffer.front(), 11);
195 }
196
197 #[test]
198 fn default_trait() {
199 let buffer = RingBuffer::<u8, 10>::default();
200 assert_eq!(buffer.size(), 0);
201 assert!(buffer.is_empty());
202 }
203
204 #[test]
205 #[should_panic(expected = "Calling pop on an empty RingBuffer")]
206 fn empty_pop_assert() {
207 let mut buffer = RingBuffer::<u8, 10>::new();
208 buffer.pop();
209 }
210
211 #[test]
212 #[should_panic(expected = "Calling front on an empty RingBuffer")]
213 fn empty_front_assert() {
214 let buffer = RingBuffer::<u8, 10>::new();
215 let _ = buffer.front();
216 }
217
218 #[test]
219 #[should_panic(expected = "Calling back on an empty RingBuffer")]
220 fn empty_back_assert() {
221 let buffer = RingBuffer::<u8, 10>::new();
222 let _ = buffer.back();
223 }
224
225 #[test]
226 #[should_panic(expected = "Calling push on a full RingBuffer")]
227 fn full_push_assert() {
228 let mut buffer = RingBuffer::<u8, 2>::new();
229 buffer.push(1);
230 buffer.push(2);
231 buffer.push(3);
232 }
233
234 #[test]
235 fn construct_destruct_match() {
236 static CONSTRUCT_COUNT: AtomicU32 = AtomicU32::new(0);
237 static DESTRUCT_COUNT: AtomicU32 = AtomicU32::new(0);
238
239 CONSTRUCT_COUNT.store(0, Ordering::Relaxed);
241 DESTRUCT_COUNT.store(0, Ordering::Relaxed);
242
243 struct TestObj;
244
245 impl TestObj {
246 fn new() -> Self {
247 CONSTRUCT_COUNT.fetch_add(1, Ordering::Relaxed);
248 TestObj
249 }
250 }
251
252 impl Drop for TestObj {
253 fn drop(&mut self) {
254 DESTRUCT_COUNT.fetch_add(1, Ordering::Relaxed);
255 }
256 }
257
258 {
259 let mut buffer = RingBuffer::<TestObj, 10>::new();
260
261 buffer.push(TestObj::new());
262 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 1);
263 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 0);
264
265 buffer.pop();
266 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 1);
267 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 1);
268
269 buffer.push(TestObj::new());
270 buffer.push(TestObj::new());
271 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 3);
272 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 1);
273
274 buffer.clear();
275 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 3);
276 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 3);
277
278 buffer.push(TestObj::new());
279 buffer.push(TestObj::new());
280 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 5);
281 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 3);
282 }
283
284 assert_eq!(CONSTRUCT_COUNT.load(Ordering::Relaxed), 5);
286 assert_eq!(DESTRUCT_COUNT.load(Ordering::Relaxed), 5);
287 }
288
289 #[test]
290 fn test_ring_buffer_capacity() {
291 assert_eq!(RingBuffer::<u8, 5>::capacity(), 5);
292 }
293
294 #[test]
295 fn test_ring_buffer_mut_accessors() {
296 let mut buffer = RingBuffer::<u8, 5>::new();
297 buffer.push(10);
298 buffer.push(20);
299 *buffer.front_mut() = 15;
300 *buffer.back_mut() = 25;
301 assert_eq!(*buffer.front(), 15);
302 assert_eq!(*buffer.back(), 25);
303 }
304
305 #[test]
306 #[should_panic(expected = "Calling front_mut on an empty RingBuffer")]
307 fn empty_front_mut_assert() {
308 let mut buffer = RingBuffer::<u8, 10>::new();
309 let _ = buffer.front_mut();
310 }
311
312 #[test]
313 #[should_panic(expected = "Calling back_mut on an empty RingBuffer")]
314 fn empty_back_mut_assert() {
315 let mut buffer = RingBuffer::<u8, 10>::new();
316 let _ = buffer.back_mut();
317 }
318}