use core::ops::{Index, IndexMut};
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::iter::FromIterator;
pub trait RingBuffer<T>: Sized {
fn len(&self) -> usize;
#[inline]
fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
fn is_full(&self) -> bool {
self.len() == self.capacity()
}
fn capacity(&self) -> usize;
}
pub trait RingBufferWrite<T>: RingBuffer<T> + Extend<T> {
fn push(&mut self, value: T);
fn enqueue(&mut self, value: T) {
self.push(value)
}
}
pub trait RingBufferRead<T>: RingBuffer<T> {
fn dequeue(&mut self) -> Option<T>;
fn skip(&mut self);
fn drain(&mut self) -> RingBufferDrainingIterator<T, Self> {
RingBufferDrainingIterator::new(self)
}
}
pub trait RingBufferExt<T>:
RingBuffer<T>
+ RingBufferRead<T>
+ RingBufferWrite<T>
+ Index<isize, Output = T>
+ IndexMut<isize>
+ FromIterator<T>
{
fn fill_with<F: FnMut() -> T>(&mut self, f: F);
fn fill_default(&mut self)
where
T: Default,
{
self.fill_with(Default::default);
}
fn fill(&mut self, value: T)
where
T: Clone,
{
self.fill_with(|| value.clone());
}
fn clear(&mut self);
fn get(&self, index: isize) -> Option<&T>;
fn get_mut(&mut self, index: isize) -> Option<&mut T>;
fn get_absolute(&self, index: usize) -> Option<&T>;
fn get_absolute_mut(&mut self, index: usize) -> Option<&mut T>;
#[inline]
fn peek(&self) -> Option<&T> {
self.front()
}
#[inline]
fn front(&self) -> Option<&T> {
self.get(0)
}
#[inline]
fn front_mut(&mut self) -> Option<&mut T> {
self.get_mut(0)
}
#[inline]
fn back(&self) -> Option<&T> {
self.get(-1)
}
#[inline]
fn back_mut(&mut self) -> Option<&mut T> {
self.get_mut(-1)
}
#[inline]
fn iter_mut(&mut self) -> RingBufferMutIterator<T, Self> {
RingBufferMutIterator::new(self)
}
#[inline]
fn iter(&self) -> RingBufferIterator<T, Self> {
RingBufferIterator::new(self)
}
#[cfg(feature = "alloc")]
fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
self.iter().cloned().collect()
}
fn contains(&self, elem: &T) -> bool
where
T: PartialEq,
{
self.iter().any(|i| i == elem)
}
}
mod iter {
use crate::{RingBufferExt, RingBufferRead};
use core::iter::FusedIterator;
use core::marker::PhantomData;
pub struct RingBufferIterator<'rb, T, RB: RingBufferExt<T>> {
obj: &'rb RB,
len: usize,
index: usize,
phantom: PhantomData<T>,
}
impl<'rb, T, RB: RingBufferExt<T>> RingBufferIterator<'rb, T, RB> {
#[inline]
pub fn new(obj: &'rb RB) -> Self {
Self {
obj,
len: obj.len(),
index: 0,
phantom: PhantomData::default(),
}
}
}
impl<'rb, T: 'rb, RB: RingBufferExt<T>> Iterator for RingBufferIterator<'rb, T, RB> {
type Item = &'rb T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.len {
let res = self.obj.get(self.index as isize);
self.index += 1;
res
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<'rb, T: 'rb, RB: RingBufferExt<T>> FusedIterator for RingBufferIterator<'rb, T, RB> {}
impl<'rb, T: 'rb, RB: RingBufferExt<T>> ExactSizeIterator for RingBufferIterator<'rb, T, RB> {}
impl<'rb, T: 'rb, RB: RingBufferExt<T>> DoubleEndedIterator for RingBufferIterator<'rb, T, RB> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len > 0 && self.index < self.len {
let res = self.obj.get((self.len - 1) as isize);
self.len -= 1;
res
} else {
None
}
}
}
pub struct RingBufferMutIterator<'rb, T, RB: RingBufferExt<T>> {
obj: &'rb mut RB,
index: usize,
phantom: PhantomData<T>,
}
impl<'rb, T, RB: RingBufferExt<T>> RingBufferMutIterator<'rb, T, RB> {
#[inline]
pub fn new(obj: &'rb mut RB) -> Self {
Self {
obj,
index: 0,
phantom: PhantomData::default(),
}
}
pub fn next(&mut self) -> Option<&mut T> {
if self.index < self.obj.len() {
let res = self.obj.get_mut(self.index as isize);
self.index += 1;
res
} else {
None
}
}
}
pub struct RingBufferDrainingIterator<'rb, T, RB: RingBufferRead<T>> {
obj: &'rb mut RB,
phantom: PhantomData<T>,
}
impl<'rb, T, RB: RingBufferRead<T>> RingBufferDrainingIterator<'rb, T, RB> {
#[inline]
pub fn new(obj: &'rb mut RB) -> Self {
Self {
obj,
phantom: PhantomData::default(),
}
}
}
impl<'rb, T, RB: RingBufferRead<T>> Iterator for RingBufferDrainingIterator<'rb, T, RB> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.obj.dequeue()
}
}
}
pub use iter::{RingBufferDrainingIterator, RingBufferIterator, RingBufferMutIterator};
macro_rules! impl_ringbuffer_read {
() => {
#[inline]
fn skip(&mut self) {
let _ = self.dequeue().map(drop);
}
};
}
macro_rules! impl_ringbuffer {
($readptr: ident, $writeptr: ident) => {
#[inline]
fn len(&self) -> usize {
self.$writeptr - self.$readptr
}
};
}
macro_rules! impl_ringbuffer_ext {
($get_unchecked: ident, $get_unchecked_mut: ident, $readptr: ident, $writeptr: ident, $mask: expr) => {
#[inline]
fn get(&self, index: isize) -> Option<&T> {
use core::ops::Not;
self.is_empty().not().then(move || {
let index_from_readptr = if index >= 0 {
index
} else {
self.len() as isize + index
};
let normalized_index =
self.readptr as isize + index_from_readptr.rem_euclid(self.len() as isize);
unsafe {
self.$get_unchecked($crate::mask(self.capacity(), normalized_index as usize))
}
})
}
#[inline]
fn get_mut(&mut self, index: isize) -> Option<&mut T> {
use core::ops::Not;
self.is_empty().not().then(move || {
let index_from_readptr = if index >= 0 {
index
} else {
self.len() as isize + index
};
let normalized_index =
self.readptr as isize + index_from_readptr.rem_euclid(self.len() as isize);
unsafe {
self.$get_unchecked_mut($crate::mask(
self.capacity(),
normalized_index as usize,
))
}
})
}
#[inline]
fn get_absolute(&self, index: usize) -> Option<&T> {
let read = $mask(self.capacity(), self.$readptr);
let write = $mask(self.capacity(), self.$writeptr);
(index >= read && index < write).then(|| unsafe {
self.$get_unchecked(index)
})
}
#[inline]
fn get_absolute_mut(&mut self, index: usize) -> Option<&mut T> {
(index >= $mask(self.capacity(), self.$readptr)
&& index < $mask(self.capacity(), self.$writeptr))
.then(move || unsafe {
self.$get_unchecked_mut(index)
})
}
#[inline]
fn clear(&mut self) {
for i in self.drain() {
drop(i);
}
self.$readptr = 0;
self.$writeptr = 0;
}
};
}