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