use arraydeque::{ArrayDeque};
use core::fmt;
use core::cmp::max;
use generic_array::{ArrayLength, GenericArray, sequence::GenericSequence};
#[derive(Debug)]
struct Iter<'a, N: ArrayLength<u8>> {
buffer: &'a Ringbuffer<N>,
index: i32,
step: i32,
}
impl<'a, N> Iterator for Iter<'a, N>
where N: ArrayLength<u8>
{
type Item = &'a[u8];
fn next(&mut self) -> Option<&'a [u8]> {
let i = self.index;
self.index = self.index + self.step;
if i < 0 {
None
} else {
self.buffer.element(i as usize)
}
}
}
#[derive(Eq, PartialEq, Debug)]
pub enum Error {
NoSpace,
}
pub struct Ringbuffer<N: ArrayLength<u8>> {
buffer: GenericArray<u8, N>,
line_pointers: ArrayDeque<[usize; 16]>,
wp: usize,
skipped: usize,
}
impl<N: ArrayLength<u8>>fmt::Debug for Ringbuffer<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Ringbuffer")
.field("wp", &self.wp)
.field("skipped", &self.skipped)
.field("free", &self.free())
.field("line_pointers", &self.line_pointers)
.field("buffer", &self.buffer)
.finish()
}
}
impl<N: ArrayLength<u8>> Ringbuffer<N> {
pub fn new() -> Self {
Self {
buffer: GenericArray::generate(|_| 0u8),
line_pointers: ArrayDeque::new(),
wp: 0,
skipped: 0,
}
}
pub fn try_add(&mut self, bytes: &[u8]) -> Result<(), Error> {
if bytes.len() > self.free() {
return Err(Error::NoSpace);
}
self.wrap_wp(bytes.len());
match self.line_pointers.push_back(self.wp) {
Ok(_) => {
for b in bytes {
self.buffer[self.wp] = *b;
self.wp += 1;
self.wp %= self.buffer.len();
}
},
Err(_err) => {
return Err(Error::NoSpace);
}
};
Ok(())
}
pub fn add(&mut self, bytes: &[u8]) {
while let Err(_err) = self.try_add(bytes) {
#[cfg(test)]
println!("No space, will pop 1 element");
if !self.pop() {
break;
}
}
}
pub fn iter(&self, offset: usize) -> impl Iterator<Item=&[u8]> {
Iter {
buffer: &self,
index: offset as i32,
step: 1,
}
}
pub fn reverse_iter(&self, offset: usize) -> impl Iterator<Item=&[u8]> {
let i = self.line_pointers.len() as i32 - offset as i32 - 1;
Iter {
buffer: &self,
index: i,
step: -1,
}
}
pub fn element(&self, index: usize) -> Option<&[u8]> {
if self.line_pointers.len() == 0 || index > self.line_pointers.len() {
return None;
}
let start = self.line_pointers[index];
#[cfg(test)]
println!("wp {}, start {}", self.wp, start);
let end = if self.wp < start {
self.buffer.len() - self.skipped
} else if self.line_pointers.len() <= index+1 {
self.wp
} else {
self.line_pointers[index+1]
};
Some(&self.buffer[start..end])
}
pub fn pop(&mut self) -> bool {
let popped = match self.line_pointers.pop_front() {
Some(i) => {
let j = match self.line_pointers.front() {
Some(el ) => *el,
None => i
};
if j < i {
#[cfg(test)]
println!("Reset skipped bytes");
self.skipped = 0;
}
true
},
None => false
};
if self.line_pointers.len() == 0 {
self.wp = 0
}
popped
}
pub fn used(&self) -> usize {
self.buffer.len() - self.free()
}
pub fn wrap_wp(&mut self, size: usize) {
let first_index: usize = match self.line_pointers.front() {
Some(&i) => i,
None => 0
};
self.wp = if self.wp >= first_index {
if self.buffer.len() - self.wp - 1 >= size {
self.wp
} else {
self.skipped = self.buffer.len() - self.wp;
0
}
} else {
self.wp
};
}
pub fn free(&self) -> usize {
let first_index: usize = match self.line_pointers.front() {
Some(&i) => i,
None => 0
};
let free = if self.wp >= first_index {
max(self.buffer.len() - self.wp, first_index)
} else {
first_index - self.wp
};
free - 1
}
}
#[cfg(test)]
#[macro_use]
extern crate std;
#[cfg(test)]
mod tests {
use super::*;
use generic_array::typenum::{U1, U2, U8, U32, U40};
#[test]
fn it_handles_full_buffer() {
let buffer: Ringbuffer::<U1> = Ringbuffer::new();
assert_eq!(buffer.free(), 0);
let mut buffer: Ringbuffer::<U2> = Ringbuffer::new();
buffer.try_add(&[1]).ok();
assert_eq!(buffer.free(), 0);
}
#[test]
fn it_knows_its_length() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
assert_eq!(buffer.free(), 7);
buffer.try_add(&[1,2,3,4]).ok();
assert_eq!(buffer.free(), 3);
buffer.try_add(&[5, 6]).ok();
assert_eq!(buffer.free(), 1);
println!("{:?}", buffer);
buffer.pop();
assert_eq!(buffer.free(), 3);
buffer.try_add(&[7, 8, 9]).ok();
assert_eq!(buffer.free(), 0);
let should_be_error = buffer.try_add(&[7, 8]).unwrap_err();
assert_eq!(should_be_error, Error::NoSpace);
}
#[test]
fn it_pops_elements_correctly() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
assert_eq!(buffer.free(), 7);
buffer.try_add(&[1,2]).ok();
buffer.try_add(&[3,4,5,6]).ok();
assert_eq!(buffer.free(), 1);
buffer.pop();
assert_eq!(buffer.free(), 1);
buffer.pop();
assert_eq!(buffer.free(), 7);
}
#[test]
fn it_returns_correct_slice() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.try_add(&[1,2]).ok();
buffer.try_add(&[3,4,3]).ok();
buffer.try_add(&[5,6]).ok();
let mut iterator = buffer.reverse_iter(0);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 5);
assert_eq!(slice[1], 6);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 3);
assert_eq!(slice[0], 3);
assert_eq!(slice[1], 4);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 1);
assert_eq!(slice[1], 2);
let slice = iterator.next();
assert_eq!(slice, None);
}
fn drop<'a>(_d: impl Iterator<Item=&'a[u8]>) {
println!("drop iterator")
}
#[test]
fn it_iterator_and_pop() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.try_add(&[1,2]).ok();
buffer.try_add(&[3,4,3]).ok();
buffer.try_add(&[5,6]).ok();
let iterator = buffer.reverse_iter(0);
drop(iterator);
buffer.pop();
}
#[test]
fn it_errors_on_overflow() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
assert_eq!(buffer.free(), 7);
buffer.try_add(&[1,2]).ok();
buffer.try_add(&[3,4,5,6]).ok();
let should_be_error = buffer.try_add(&[7, 8]).unwrap_err();
assert_eq!(should_be_error, Error::NoSpace);
let mut buffer: Ringbuffer::<U32> = Ringbuffer::new();
for i in 0..16 {
buffer.try_add(&[i]).unwrap();
}
let should_be_error = buffer.try_add(&[0xEE]).unwrap_err();
assert_eq!(should_be_error, Error::NoSpace);
}
#[test]
fn it_correctly_wraps_write_pointer() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.add(&[1,2,3,4]);
buffer.add(&[5,6]);
let f = buffer.free();
assert_eq!(f, 1);
buffer.pop();
let f = buffer.free();
assert_eq!(f, 3);
buffer.add(&[7,8]);
let f = buffer.free();
assert_eq!(buffer.free(), 1);
}
#[test]
fn it_wrapps() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.add(&[1,2]);
buffer.add(&[3,4,3]);
buffer.add(&[5,6]);
let mut iterator = buffer.reverse_iter(0);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 5);
assert_eq!(slice[1], 6);
drop(iterator);
buffer.add(&[7,8]);
println!("{:?}", buffer);
let mut iterator = buffer.iter(0);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 5);
assert_eq!(slice[1], 6);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 7);
assert_eq!(slice[1], 8);
}
#[test]
fn it_access_last_element_when_wp_is_wraped() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.add(&[1,2]);
buffer.add(&[3,4,3]);
buffer.add(&[5,6]);
buffer.pop();
buffer.free();
buffer.wrap_wp(2);
buffer.free();
let mut iterator = buffer.reverse_iter(0);
let slice = iterator.next().unwrap();
assert_eq!(slice.len(), 2);
assert_eq!(slice[0], 5);
assert_eq!(slice[1], 6);
}
#[test]
fn it_resets_skipped_bytes() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.add(&[1,2]);
buffer.add(&[3,4]);
buffer.add(&[5,6]);
buffer.add(&[7,8]);
buffer.pop();
println!("{:?}", buffer);
buffer.add(&[1,2,3,4,5]);
buffer.add(&[9,9]);
println!("{:?}", buffer);
let mut iterator = buffer.reverse_iter(0);
let slice = iterator.next().unwrap();
}
#[test]
fn it_handles_zero_length_gracefully() {
let buffer: Ringbuffer::<U8> = Ringbuffer::new();
let mut iterator = buffer.reverse_iter(0);
let slice = iterator.next();
assert_eq!(slice, None);
println!("{:?}", slice);
drop(iterator);
let mut iterator = buffer.reverse_iter(1);
let slice = iterator.next();
assert_eq!(slice, None);
println!("{:?}", slice);
drop(iterator);
let mut iterator = buffer.iter(0);
let slice = iterator.next();
assert_eq!(slice, None);
println!("{:?}", slice);
drop(iterator);
}
#[test]
fn it_handles_index_larger_than_len() {
let mut buffer: Ringbuffer::<U8> = Ringbuffer::new();
buffer.add(&[9,9,9,9,9]);
let mut iterator = buffer.reverse_iter(2);
let slice = iterator.next();
assert_eq!(slice, None);
drop(iterator);
let mut iterator = buffer.iter(2);
let slice = iterator.next();
assert_eq!(slice, None);
}
#[test]
fn it_handles_real_world_example() {
let mut buffer: Ringbuffer::<U40> = Ringbuffer::new();
buffer.add(&[1,1,255]);
buffer.add(&[2,2,255]);
buffer.add(&[3,3, 255]);
let a4 = [4u8; 30];
buffer.add(&a4);
assert_eq!(buffer.free(), 0);
}
}