pub struct RingBuffer<T, const SIZE: usize> { /* private fields */ }
Expand description
Ring buffer using a boxed array as backing storage. This has the adantage that conversions
from Vec
or to VecDeque
are nearly free.
Main use case of this is as a replacement for std::collection::VecDeque
in cases where the
size is fixed at compile time and one really wants to make invalid states impossible.
Due to this, the only way to put a new item into the buffer is to take an old item out.
There is intentionally no way to temporary ownership of items. If you need such an API, you can
use the get_mut()
method or the index operator to obtain a
mutable reference, and then use either methods from std::mem
to temporarily place another
value there, or use internally unsafe solutions like the replace_with
crate.
§Examples
Whenever you push_pop()
, the buffer moves to the next element. You can get a reference to
contained data using the index operator, or if you want a panic-free way, using the
get()
or get_mut()
methods.
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).expect("Works, enough input.");
assert_eq!(buf[0], &42);
assert_eq!(buf[1], &37);
assert_eq!(buf[2], &23);
assert_eq!(buf[3], &12);
assert_eq!(buf.get(3), Some(&&12));
assert_eq!(buf.get(4), None);
let (buf, forty_two) = buf.push_pop(&1);
assert_eq!(forty_two, &42);
assert_eq!(buf[0], &37);
assert_eq!(buf[1], &23);
assert_eq!(buf[2], &12);
assert_eq!(buf[3], &1);
let (buf, thirty_seven) = buf.push_pop(&2);
assert_eq!(thirty_seven, &37);
let (buf, twenty_three) = buf.push_pop(&3);
assert_eq!(twenty_three, &23);
let (buf, twelve) = buf.push_pop(&4);
assert_eq!(twelve, &12);
let (buf, one) = buf.push_pop(&5);
assert_eq!(one, &1);
assert_eq!(buf[0], &2);
assert_eq!(buf[1], &3);
assert_eq!(buf[2], &4);
assert_eq!(buf[3], &5);
Implementations§
Source§impl<T, const SIZE: usize> RingBuffer<T, SIZE>
impl<T, const SIZE: usize> RingBuffer<T, SIZE>
Sourcepub fn push_pop(self, new_entry: T) -> (Self, T)
pub fn push_pop(self, new_entry: T) -> (Self, T)
Puts new_entry
into the ring buffer at its current location, and returns the value that
was there before. Then moves the ring buffer to the next location.
§Examples
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).expect("Works, enough input.");
assert_eq!(buf[0], &42);
assert_eq!(buf[3], &12);
let (buf, forty_two) = buf.push_pop(&1);
assert_eq!(forty_two, &42);
assert_eq!(buf[0], &37);
assert_eq!(buf[3], &1);
Sourcepub fn new<I>(input: I) -> Result<Self, Box<[T]>>where
I: Iterator<Item = T>,
pub fn new<I>(input: I) -> Result<Self, Box<[T]>>where
I: Iterator<Item = T>,
Creates a new RingBuffer from an Iterator
. If the iterator does not supply enough
elements, the elements that have already been taken from the iterator are instead returned
in the Err
variant as a boxed slice.
§Warning
Beware that it is not considered an error if the iterator would yield more elements. If you
need the remaining data in the iterator, make sure to pass it
by_ref()
.
§Examples
If the iterator has at least the required number of elements, a ring buffer is created.
let input = [42,37,23,12,8];
let mut iter = input.iter();
let buf : RingBuffer<&usize, 4> = RingBuffer::new(iter.by_ref()).expect("Works, enough input.");
assert_eq!(iter.next(), Some(&8));
assert_eq!(buf[0], &42);
assert_eq!(buf[1], &37);
assert_eq!(buf[2], &23);
assert_eq!(buf[3], &12);
assert_eq!(buf.get(4),None);
If the iterator does not yield enough elements, an error is returned, containing all elements taken from the iterator.
let input = ["lizard", "fish", "bird"];
let buf : Result<RingBuffer<&str, 4>, _> = RingBuffer::new(input.iter().map(|x| *x));
assert!(buf.is_err());
assert_eq!(buf.unwrap_err()[1], "fish");
Sourcepub fn new_copy(init: T) -> Selfwhere
T: Copy,
pub fn new_copy(init: T) -> Selfwhere
T: Copy,
Initializes the ring buffer with copies of the same value.
§Examples
let buf :RingBuffer<usize,4> = RingBuffer::new_copy(3);
assert_eq!(buf[0], 3);
assert_eq!(buf[1], 3);
assert_eq!(buf[2], 3);
assert_eq!(buf[3], 3);
assert_eq!(buf.get(4), None);
Sourcepub fn get(&self, index: usize) -> Option<&T>
pub fn get(&self, index: usize) -> Option<&T>
Gets an immutable reference to the entry that’s index
elements in the future of the
buffer. In other words get(0)
returns an immutable reference to the next element that
would be returned by push_pop()
, get(1)
to the second-next and
so on. Return value is wrapped in an option due to range checking. You can use the index
operator []
instead if you are sure your index is valid.
§Examples
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).expect("Works, enough input.");
let (buf, _) = buf.push_pop(&7);
assert_eq!(buf.get(0), Some(&&37));
assert_eq!(buf.get(3), Some(&&7));
assert_eq!(buf.get(4), None);
Sourcepub fn get_mut(&mut self, index: usize) -> Option<&mut T>
pub fn get_mut(&mut self, index: usize) -> Option<&mut T>
Similar to get()
, but yields a mutable reference instead.
§Examples
let input = [42,37,23,12];
let mut buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).expect("Works, enough input.");
match buf.get_mut(0) {
Some(x) => {
assert_eq!(**x, 42);
*x = &1;
}
_ => {
unreachable!();
}
}
assert_eq!(buf.get(0), Some(&&1));
Sourcepub fn iter(&self) -> RingBufferIterator<'_, T, SIZE> ⓘ
pub fn iter(&self) -> RingBufferIterator<'_, T, SIZE> ⓘ
Returns an Iterator
over references to the contained elements.
§Examples
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).expect("Works, enough input");
let (buf, forty_two) = buf.push_pop(&1);
assert_eq!(forty_two, &42);
assert!(buf.iter().map(|x| *x).eq([37,23,12,1].iter()));
Trait Implementations§
Source§impl<T: Clone, const SIZE: usize> Clone for RingBuffer<T, SIZE>
impl<T: Clone, const SIZE: usize> Clone for RingBuffer<T, SIZE>
Source§fn clone(&self) -> RingBuffer<T, SIZE>
fn clone(&self) -> RingBuffer<T, SIZE>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl<T, const SIZE: usize> From<RingBuffer<T, SIZE>> for VecDeque<T>
impl<T, const SIZE: usize> From<RingBuffer<T, SIZE>> for VecDeque<T>
Source§fn from(buffer: RingBuffer<T, SIZE>) -> VecDeque<T>
fn from(buffer: RingBuffer<T, SIZE>) -> VecDeque<T>
Conversion from a RingBuffer<T, const SIZE :usize>
into a
VecDeque<T>
. This works without re-allocations and cannot fail.
§Examples
use std::collections::VecDeque;
let a = vec![42,37,23,12];
let buf : RingBuffer<_, 4> = a.try_into().expect("Works, size matches.");
let (buf, _) = buf.push_pop(5);
let deque : VecDeque<_> = buf.into();
assert_eq!(deque[0], 37);
assert_eq!(deque[3], 5);
Source§impl<T, const SIZE: usize> Index<usize> for RingBuffer<T, SIZE>
impl<T, const SIZE: usize> Index<usize> for RingBuffer<T, SIZE>
Source§fn index(&self, index: usize) -> &T
fn index(&self, index: usize) -> &T
Indexing operation in an immutable context. Internally uses get()
.
Indices start at the value that would be replaced/returned by the next call to
push_pop()
.
§Examples
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).unwrap();
let (buf, _) = buf.push_pop(&123);
assert_eq!(buf[0],&37);
assert_eq!(buf[3],&123);
§Panics
If the index is out of range (larger than or equal to SIZE
), this panics. Use
get()
if you want sane behaviour.
Source§impl<T, const SIZE: usize> IndexMut<usize> for RingBuffer<T, SIZE>
impl<T, const SIZE: usize> IndexMut<usize> for RingBuffer<T, SIZE>
Source§fn index_mut(&mut self, index: usize) -> &mut T
fn index_mut(&mut self, index: usize) -> &mut T
Indexing operation in a mutable context. Internally uses get_mut()
.
Indices start at the value that would be replaced/returned by the next call to
push_pop()
.
§Examples
let input = [42,37,23,12];
let mut buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).unwrap();
buf[1] = &0;
assert_eq!(buf[1], &0);
let (buf, forty_two) = buf.push_pop(&3);
assert_eq!(forty_two, &42);
let (buf, zero) = buf.push_pop(&4);
assert_eq!(zero, &0);
§Panics
If the index is out of range (larger than or equal to SIZE
), this panics. Use
get_mut()
if you want sane behaviour.
Source§impl<'b, T, const SIZE: usize> IntoIterator for &'b RingBuffer<T, SIZE>
impl<'b, T, const SIZE: usize> IntoIterator for &'b RingBuffer<T, SIZE>
Source§fn into_iter(self) -> Self::IntoIter
fn into_iter(self) -> Self::IntoIter
Wrapper around the RingBuffer::iter()
to enable for-loop compatibility for
&RingBuffer
.
§Example
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).unwrap();
let (buf, forty_two) = buf.push_pop(&1);
assert_eq!(forty_two, &42);
let reference = &buf;
assert!(reference.into_iter().map(|x| *x).eq([37,23,12,1].iter()));
Source§type IntoIter = RingBufferIterator<'b, T, SIZE>
type IntoIter = RingBufferIterator<'b, T, SIZE>
Source§impl<T, const SIZE: usize> IntoIterator for RingBuffer<T, SIZE>
impl<T, const SIZE: usize> IntoIterator for RingBuffer<T, SIZE>
Source§fn into_iter(self) -> Self::IntoIter
fn into_iter(self) -> Self::IntoIter
Consumes the ring buffer into an Iterator
. This conversion works without reallocation.
§Example
let input = [42,37,23,12];
let buf : RingBuffer<&usize, 4> = RingBuffer::new(input.iter()).unwrap();
let (buf, forty_two) = buf.push_pop(&1);
assert_eq!(forty_two, &42);
assert!(buf.into_iter().eq([37,23,12,1].iter()));
Source§impl<T, const SIZE: usize> TryFrom<Box<[T]>> for RingBuffer<T, SIZE>
impl<T, const SIZE: usize> TryFrom<Box<[T]>> for RingBuffer<T, SIZE>
Source§fn try_from(slice: Box<[T]>) -> Result<Self, Self::Error>
fn try_from(slice: Box<[T]>) -> Result<Self, Self::Error>
Conversion from a boxed slice. This works without a re-allocation. Returns the input as Err
in case the size does not match. Opposed to the new()
method that takes an
Iterator
this conversion fails if the input has more elements than fit into the ring buffer.
§Examples
let a : Box<[_]> = vec![42,37,23,12].into();
let buf : RingBuffer<_, 4> = a.try_into().expect("Works, size matches.");
assert_eq!(buf[0], 42);
assert_eq!(buf[1], 37);
assert_eq!(buf[2], 23);
assert_eq!(buf[3], 12);
assert_eq!(buf.get(4),None);
let b : Box<[_]> = vec![42,37,23,12].into();
let b_cpy = b.clone();
let buf2 : Result<RingBuffer<_,3>,_> = b.try_into();
assert_eq!(buf2.unwrap_err(), b_cpy);
Source§impl<T, const SIZE: usize> TryFrom<Vec<T>> for RingBuffer<T, SIZE>
impl<T, const SIZE: usize> TryFrom<Vec<T>> for RingBuffer<T, SIZE>
Source§fn try_from(vector: Vec<T>) -> Result<Self, Self::Error>
fn try_from(vector: Vec<T>) -> Result<Self, Self::Error>
Conversion from a Vec
. This works without re-allocation. Returns the input as Err
in case
the size does not match. Opposed to the new()
method that takes an
Iterator
this conversion fails if the input has more elements than fit into the ring buffer.
§Examples
let a = vec![42,37,23,12];
let buf : RingBuffer<_, 4> = a.try_into().expect("Works, size matches.");
assert_eq!(buf[0], 42);
assert_eq!(buf[1], 37);
assert_eq!(buf[2], 23);
assert_eq!(buf[3], 12);
assert_eq!(buf.get(4),None);
let b = vec![42,37,23,12];
let b_cpy = b.clone();
let buf2 : Result<RingBuffer<_,3>,_> = b.try_into();
assert_eq!(buf2.unwrap_err(), b_cpy);