| pub struct RingBuffer<const N: usize> { |
| buf: [u8; N], |
| start: usize, |
| end: usize, |
| empty: bool, |
| } |
| |
| impl<const N: usize> RingBuffer<N> { |
| pub const fn new() -> Self { |
| Self { |
| buf: [0; N], |
| start: 0, |
| end: 0, |
| empty: true, |
| } |
| } |
| |
| pub fn push_buf(&mut self) -> &mut [u8] { |
| if self.start == self.end && !self.empty { |
| trace!(" ringbuf: push_buf empty"); |
| return &mut self.buf[..0]; |
| } |
| |
| let n = if self.start <= self.end { |
| self.buf.len() - self.end |
| } else { |
| self.start - self.end |
| }; |
| |
| trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); |
| &mut self.buf[self.end..self.end + n] |
| } |
| |
| pub fn push(&mut self, n: usize) { |
| trace!(" ringbuf: push {:?}", n); |
| if n == 0 { |
| return; |
| } |
| |
| self.end = self.wrap(self.end + n); |
| self.empty = false; |
| } |
| |
| pub fn pop_buf(&mut self) -> &mut [u8] { |
| if self.empty { |
| trace!(" ringbuf: pop_buf empty"); |
| return &mut self.buf[..0]; |
| } |
| |
| let n = if self.end <= self.start { |
| self.buf.len() - self.start |
| } else { |
| self.end - self.start |
| }; |
| |
| trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); |
| &mut self.buf[self.start..self.start + n] |
| } |
| |
| pub fn pop(&mut self, n: usize) { |
| trace!(" ringbuf: pop {:?}", n); |
| if n == 0 { |
| return; |
| } |
| |
| self.start = self.wrap(self.start + n); |
| self.empty = self.start == self.end; |
| } |
| |
| pub fn is_full(&self) -> bool { |
| self.start == self.end && !self.empty |
| } |
| |
| pub fn is_empty(&self) -> bool { |
| self.empty |
| } |
| |
| #[allow(unused)] |
| pub fn len(&self) -> usize { |
| if self.empty { |
| 0 |
| } else if self.start < self.end { |
| self.end - self.start |
| } else { |
| N + self.end - self.start |
| } |
| } |
| |
| pub fn clear(&mut self) { |
| self.start = 0; |
| self.end = 0; |
| self.empty = true; |
| } |
| |
| fn wrap(&self, n: usize) -> usize { |
| assert!(n <= self.buf.len()); |
| if n == self.buf.len() { |
| 0 |
| } else { |
| n |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| #[test] |
| fn push_pop() { |
| let mut rb: RingBuffer<4> = RingBuffer::new(); |
| let buf = rb.push_buf(); |
| assert_eq!(4, buf.len()); |
| buf[0] = 1; |
| buf[1] = 2; |
| buf[2] = 3; |
| buf[3] = 4; |
| rb.push(4); |
| |
| let buf = rb.pop_buf(); |
| assert_eq!(4, buf.len()); |
| assert_eq!(1, buf[0]); |
| rb.pop(1); |
| |
| let buf = rb.pop_buf(); |
| assert_eq!(3, buf.len()); |
| assert_eq!(2, buf[0]); |
| rb.pop(1); |
| |
| let buf = rb.pop_buf(); |
| assert_eq!(2, buf.len()); |
| assert_eq!(3, buf[0]); |
| rb.pop(1); |
| |
| let buf = rb.pop_buf(); |
| assert_eq!(1, buf.len()); |
| assert_eq!(4, buf[0]); |
| rb.pop(1); |
| |
| let buf = rb.pop_buf(); |
| assert_eq!(0, buf.len()); |
| |
| let buf = rb.push_buf(); |
| assert_eq!(4, buf.len()); |
| } |
| } |