1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4pub struct BytearrayRingbuffer<const N: usize> {
5 buffer: [u8; N],
6 head: usize,
8 tail: usize,
10 count: usize,
12}
13
14#[derive(Copy, Clone, Debug)]
15pub struct NotEnoughSpaceError;
16
17impl<const N: usize> BytearrayRingbuffer<N> {
18 pub const fn new() -> Self {
20 assert!(N > 8);
21 assert!(N < (u32::MAX as usize));
22 Self {
23 buffer: [0; N],
24 head: 0,
25 tail: 0,
26 count: 0,
27 }
28 }
29
30 pub const fn free(&self) -> usize {
32 self.bytes_unused().saturating_sub(8)
33 }
34
35 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
37 self._push(data, false)
38 }
39
40 pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
42 self._push(data, true)
43 }
44
45 #[inline(always)]
46 pub const fn empty(&self) -> bool {
47 self.count == 0
48 }
49
50 const fn bytes_unused(&self) -> usize {
52 if self.empty() {
53 N
54 } else if self.head > self.tail {
55 N + self.tail - self.head
56 } else {
57 self.tail - self.head
58 }
59 }
60
61 fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
62 assert!(data.len() <= u32::MAX as usize);
63
64 if data.len() > N - 8 {
66 return Err(NotEnoughSpaceError);
67 }
68
69 if (data.len() + 8) > self.bytes_unused() {
71 if !force {
72 return Err(NotEnoughSpaceError);
73 }
74 while (data.len() + 8) > self.bytes_unused() {
75 self.pop_front();
76 }
77 }
78
79 let addr_a = self.head;
81 let addr_b = add_wrapping::<N>(self.head, 4);
82 let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
83 let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
84 write_wrapping(&mut self.buffer, addr_a, &len_buffer);
85 write_wrapping(&mut self.buffer, addr_b, data);
86 write_wrapping(&mut self.buffer, addr_c, &len_buffer);
87
88 self.head = add_wrapping::<N>(self.head, 8 + data.len());
89 self.count += 1;
90
91 Ok(())
92 }
93
94 pub fn pop_front(&mut self) -> Option<(&[u8], &[u8])> {
96 if self.empty() {
97 return None;
98 }
99 let mut len_buffer = [0; 4];
100 read_wrapping(&self.buffer, self.tail, &mut len_buffer);
101 let len = u32::from_ne_bytes(len_buffer) as usize;
102
103 let index_data = add_wrapping::<N>(self.tail, 4);
104 let len_a = (N - index_data).min(len);
105 let a = &self.buffer[index_data..index_data + len_a];
106 let b = if len_a == len {
107 &[]
108 } else {
109 &self.buffer[..len - len_a]
110 };
111
112 self.tail = add_wrapping::<N>(self.tail, len + 8);
113 self.count -= 1;
114 Some((a, b))
115 }
116
117 pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
119 IterBackwards {
120 buffer: &self.buffer,
121 head: self.head,
122 count: self.count,
123 }
124 }
125
126 pub fn iter<'a>(&'a self) -> Iter<'a, N> {
128 Iter {
129 buffer: &self.buffer,
130 head: self.head,
131 tail: self.tail,
132 count: self.count,
133 }
134 }
135
136 #[inline(always)]
138 pub const fn count(&self) -> usize {
139 self.count
140 }
141
142 pub fn nth(&self, n: usize) -> Option<(&[u8], &[u8])> {
144 self.iter().nth(n)
145 }
146
147 pub fn nth_reverse(&self, n: usize) -> Option<(&[u8], &[u8])> {
149 self.iter_backwards().nth(n)
150 }
151
152 pub fn nth_contiguous(&mut self, mut n: usize) -> Option<&[u8]> {
154 if self.empty() {
155 return None;
156 }
157
158 let mut tail = self.tail;
160 let len_data = loop {
161 let mut buf = [0u8; 4];
162 read_wrapping(&self.buffer, tail, &mut buf);
163 let len_data = u32::from_ne_bytes(buf) as usize;
164
165 if n == 0 {
166 break len_data;
167 }
168 n -= 1;
169
170 tail = add_wrapping::<N>(tail, len_data + 8);
171 };
172
173 let index_data = add_wrapping::<N>(tail, 4);
174
175 if index_data + len_data <= N {
177 return Some(&self.buffer[index_data..index_data + len_data]);
178 }
179
180 self.buffer.rotate_left(index_data);
182 self.tail = sub_wrapping::<N>(self.tail, index_data);
183 self.head = sub_wrapping::<N>(self.head, index_data);
184
185 Some(&self.buffer[..len_data])
186 }
187}
188
189pub struct IterBackwards<'a, const N: usize> {
190 buffer: &'a [u8; N],
191 head: usize,
192 count: usize,
193}
194
195impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
196 type Item = (&'a [u8], &'a [u8]);
197
198 fn next(&mut self) -> Option<Self::Item> {
199 if self.count == 0 {
200 return None;
201 }
202
203 let index_len = sub_wrapping::<N>(self.head, 4);
205 let mut buf = [0u8; 4];
206 read_wrapping(self.buffer, index_len, &mut buf);
207 let len_data = u32::from_ne_bytes(buf) as usize;
208 debug_assert!((len_data + 8) <= N);
209
210 #[cfg(test)]
211 {
212 let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
213 let mut buf = [0u8; 4];
214 read_wrapping(self.buffer, index_len, &mut buf);
215 let len_2 = u32::from_ne_bytes(buf) as usize;
216 assert_eq!(len_data, len_2);
217 }
218
219 let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
221 let first = (N - index_data).min(len_data);
222 let slice_a = &self.buffer[index_data..index_data + first];
223 let slice_b = if first < len_data {
224 &self.buffer[..len_data - first]
225 } else {
226 &[]
227 };
228
229 self.head = sub_wrapping::<N>(self.head, 8 + len_data);
230 self.count -= 1;
231
232 Some((slice_a, slice_b))
233 }
234}
235
236impl<const N: usize> Default for BytearrayRingbuffer<N> {
237 fn default() -> Self {
238 Self::new()
239 }
240}
241
242pub struct Iter<'a, const N: usize> {
243 buffer: &'a [u8; N],
244 head: usize,
245 tail: usize,
246 count: usize,
247}
248
249impl<'a, const N: usize> Iterator for Iter<'a, N> {
250 type Item = (&'a [u8], &'a [u8]);
251
252 fn next(&mut self) -> Option<Self::Item> {
253 if self.count == 0 {
254 return None;
255 }
256
257 let bytes_used = if self.head > self.tail {
259 N + self.tail - self.head
260 } else {
261 self.tail - self.head
262 };
263 let bytes_valid = N - bytes_used;
264 debug_assert!(bytes_valid >= 8);
265
266 let mut buf = [0u8; 4];
268 read_wrapping(self.buffer, self.tail, &mut buf);
269 let len_data = u32::from_ne_bytes(buf) as usize;
270 debug_assert!((len_data + 8) <= N);
271 debug_assert!((len_data + 8) <= bytes_valid);
272
273 let index_data = add_wrapping::<N>(self.tail, 4);
275 let first = (N - index_data).min(len_data);
276 let slice_a = &self.buffer[index_data..index_data + first];
277 let slice_b = if first < len_data {
278 &self.buffer[..len_data - first]
279 } else {
280 &[]
281 };
282
283 self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
284 self.count -= 1;
285
286 Some((slice_a, slice_b))
287 }
288}
289
290fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
291 debug_assert!(addr < N);
292 debug_assert!(offset <= N);
293 let s = addr + offset;
294 if s < N { s } else { s - N }
295}
296
297fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
298 debug_assert!(addr < N);
299 debug_assert!(offset <= N);
300 if addr >= offset {
301 addr - offset
302 } else {
303 N + addr - offset
304 }
305}
306
307fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
309 let first = (buffer.len() - index).min(data.len());
310 buffer[index..index + first].copy_from_slice(&data[..first]);
311 if first < data.len() {
312 buffer[..data.len() - first].copy_from_slice(&data[first..]);
313 }
314}
315
316fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
317 let first = (buffer.len() - index).min(data.len());
318 data[..first].copy_from_slice(&buffer[index..index + first]);
319 if first < data.len() {
320 let remaining = data.len() - first;
321 data[first..].copy_from_slice(&buffer[..remaining]);
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use std::collections::VecDeque;
328
329 use super::BytearrayRingbuffer;
330
331 #[test]
332 fn push_some_packets() {
333 const N: usize = 64;
334 for start_offset in 0..N {
335 let mut buf = BytearrayRingbuffer::<N>::new();
336 buf.head = start_offset;
337 buf.tail = start_offset;
338
339 let free = 64 - 8;
340 assert_eq!(buf.free(), free);
341
342 buf.push(b"01234567").unwrap();
343 let free = free - 8 - 8;
344 assert_eq!(buf.free(), free);
345
346 buf.push(b"").unwrap();
347 let free = free - 8;
348 assert_eq!(buf.free(), free);
349
350 buf.push(b"0123").unwrap();
351 let free = free - 4 - 8;
352 assert_eq!(buf.free(), free);
353
354 buf.push(b"0123").unwrap();
355 let free = free - 4 - 8;
356 assert_eq!(buf.free(), free);
357 }
358 }
359
360 #[test]
361 fn push_force() {
362 let mut buf = BytearrayRingbuffer::<16>::new();
363 assert_eq!(buf.bytes_unused(), 16);
364
365 let a = b"012345";
366 let b = b"0123";
367
368 buf.push(a).unwrap();
369 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
370
371 buf.push(b).unwrap_err();
372 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
373
374 buf.push_force(b).unwrap();
375 assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
376 }
377
378 #[test]
379 fn push_all_data_lengths() {
380 for n in 0..(32 - 8) {
381 let mut buf = BytearrayRingbuffer::<32>::new();
382 let data = (0..n as u8).collect::<Vec<u8>>();
384
385 assert_eq!(buf.free(), 32 - 8);
386 buf.push(&data).unwrap();
387 assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
388 }
389 }
390
391 #[test]
392 fn push_sum_of_lengths_possible() {
393 let mut buf = BytearrayRingbuffer::<32>::new();
394 assert_eq!(buf.free(), 32 - 8);
396 buf.push(b"01234567").unwrap();
397 assert_eq!(buf.free(), 32 - 8 - 16);
398 buf.push(b"01234567").unwrap();
399 assert_eq!(buf.free(), 0);
400 }
401
402 #[test]
403 fn push_pop() {
404 const N: usize = 64;
405 for start_offset in 0..N {
406 eprintln!("--------------");
407 let mut buf = BytearrayRingbuffer::<N>::new();
408 buf.head = start_offset;
409 buf.tail = start_offset;
410
411 let data = b"01234567";
412 buf.push(data).unwrap();
413
414 let (a, b) = buf.pop_front().unwrap();
415 let mut out = Vec::new();
416 out.extend_from_slice(a);
417 out.extend_from_slice(b);
418
419 dbg!(out.as_slice());
420 assert!(data == out.as_slice());
421
422 assert_eq!(buf.head, buf.tail);
423 assert_eq!(buf.bytes_unused(), N);
424 }
425 }
426
427 #[test]
428 fn push_read_back() {
429 let data = [b"hello world" as &[u8], b"", b"test"];
430
431 const N: usize = 64;
432 for start_offset in 0..N {
433 let mut buf = BytearrayRingbuffer::<N>::new();
434 buf.head = start_offset;
435 buf.tail = start_offset;
436
437 for &d in &data {
438 buf.push(d).unwrap();
439 }
440
441 let mut it = buf.iter();
443 for &d in data.iter() {
444 let (a, b) = it.next().unwrap();
445 let mut ab = Vec::new();
446 ab.extend_from_slice(a);
447 ab.extend_from_slice(b);
448 let ab = ab.as_slice();
449 assert_eq!(d, ab);
450 }
451 assert_eq!(it.next(), None);
452
453 let mut it = buf.iter_backwards();
455 for &d in data.iter().rev() {
456 let (a, b) = it.next().unwrap();
457 let mut ab = Vec::new();
458 ab.extend_from_slice(a);
459 ab.extend_from_slice(b);
460 let ab = ab.as_slice();
461 assert_eq!(d, ab);
462 }
463 assert_eq!(it.next(), None);
464 }
465 }
466
467 #[test]
468 fn push_count() {
469 let mut buf = BytearrayRingbuffer::<64>::new();
470 buf.push(b"1234").unwrap();
471 assert_eq!(buf.count(), 1);
472 buf.push(b"1234").unwrap();
473 assert_eq!(buf.count(), 2);
474 buf.push(b"1234").unwrap();
475 assert_eq!(buf.count(), 3);
476 }
477
478 fn test_with_readback<const N: usize>(words: &[&'static str]) {
479 eprintln!("--------------------------");
480 let mut buf = BytearrayRingbuffer::<N>::new();
481 let mut current_words = VecDeque::new();
482 for &word in words {
483 eprintln!("adding {word:?}");
484 let word = word.to_owned();
485 let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
486 if current_bytes + 8 + word.len() > N {
487 current_words.pop_front();
488 }
489
490 buf.push_force(word.as_bytes()).unwrap();
491 current_words.push_back(word);
492
493 for (a, b) in buf.iter_backwards().zip(current_words.iter().rev()) {
494 eprintln!("read back {b:?}");
495 let mut st = String::new();
496 st.push_str(core::str::from_utf8(a.0).unwrap());
497 st.push_str(core::str::from_utf8(a.1).unwrap());
498 assert_eq!(st, *b);
499 }
500 }
501 }
502
503 #[test]
504 fn readback_various() {
505 test_with_readback::<32>(&["ab", "123", "hello", "world"]);
506 test_with_readback::<32>(&["", "", "a", "", "", ""]);
507 test_with_readback::<32>(&["", "", "ab", "", "", ""]);
508 test_with_readback::<32>(&["", "", "abc", "", "", ""]);
509 test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
510 test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
511
512 test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
513 test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
514 test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
515 test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
516 test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
517 test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
518 test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
519 }
520
521 #[test]
522 fn rotate_contiguous() {
523 const N: usize = 48;
524 let data: [&[u8]; _] = [b"012345", b"hello world", b"xyz"];
525
526 for offset in 0..N {
527 let mut buf = BytearrayRingbuffer::<N>::new();
528 buf.head = offset;
529 buf.tail = offset;
530
531 for &d in &data {
532 buf.push(d).unwrap();
533 }
534
535 let read = buf.nth_contiguous(1).unwrap();
536 assert_eq!(data[1], read);
537
538 for (&r, (a, b)) in data.iter().zip(buf.iter()) {
540 let mut out = Vec::new();
541 out.extend_from_slice(a);
542 out.extend_from_slice(b);
543 assert_eq!(out.as_slice(), r);
544 }
545 }
546 }
547}