Expand description
Ring buffer that uses a boxed array as backing storage. This guarantees that the buffers size is
always exactly at the compile-time constant value. There is no way to get fewer or more entries.
In addition, by having the array boxed, conversion from Vec
and to
VecDeque
are nearly free.
This crate does not use any unsafe code (however the IntoIterator implementation does so
indirectly, as it internally uses a VecDeque
).
Since the ring buffer has always a guaranteed number of elements, it must be initialized, either
from an iterator, a boxed slice (most collections can convert into a boxed slice at very low
cost), a Vec
, or at a value that implements Copy
.
§Examples
A new ring buffer can only be created from a Vec
or a boxed slice
of the correct size (using TryFrom
/TryInto
),
by taking the correct size from an iterator (using new()
),
or by initializing all entries in the ring buffer to the same Copy
able
value (using new_copy()
).
let buf : RingBuffer<_, 4> = vec![42,37,23,12].try_into().expect("Works, size matches.");
let wrong_size : Result<RingBuffer<_,3>, Vec<u8>> = vec![42,37,23,12].try_into();
assert!(wrong_size.is_err());
let buf2 : RingBuffer<_,3> = RingBuffer::new(vec![42,37,23,12].into_iter())
.expect("works, because iterator has enough elements - use by_ref() on iterator if \
you need the remaining elements still.");
let not_enough : Result<RingBuffer<_,5>,_> = RingBuffer::new(vec![42,37,23,12].into_iter());
assert_eq!(not_enough.unwrap_err()[2],23);
let buf3 : RingBuffer<_,3> = RingBuffer::new_copy(42);
assert_eq!(buf3[2],42);
As you have seen above, accessing upcoming elements can be done with the Index
or
IndexMut
syntax. Howver, if you are not absolutely certain that your index is within the
size of the ring buffer, you can also use the get()
or
get_mut()
methods. The indices are always relevant to the current
position within the RingBuffer.
let buf : RingBuffer<_, 4> = vec![42,37,23,12].try_into().expect("Works, size matches.");
assert_eq!(buf[3], 12);
assert_eq!(buf.get(2), Some(&23));
let mut buf = buf;
assert_eq!(buf.get_mut(4), None);
let (buf, forty_two) = buf.push_pop(6);
assert_eq!(buf[3],6);
In order to add a new element to the buffer and remove the oldest element from the buffer (after
all, the size of the RingBuffer has to be constant), you can use the
push_pop()
method:
let buf : RingBuffer<_, 4> = vec![42,37,23,12].try_into().expect("Works, size matches.");
let (buf, forty_two) = buf.push_pop(6);
assert_eq!(forty_two, 42);
assert_eq!(buf[0],37);
assert_eq!(buf[3],6);
To iterate over the upcoming elements, you can either use the iter()
or
the `into_iter() methods, the latter if you want the iterator to take
ownership of the data of the ring buffer.
let buf : RingBuffer<_, 4> = vec![42,37,23,12].try_into().expect("Works, size matches.");
assert!(buf.iter().eq(vec![42,37,23,12].iter()));
assert!(buf.into_iter().eq(vec![42,37,23,12].into_iter()));
And last, but not least, once you are done utilizing the ring buffer’s guarantee that the amount
of items is constant, you can always convert it to a VecDeque
without needing a reallocation.
let buf : RingBuffer<_, 4> = vec![42,37,23,12].try_into().expect("Works, size matches.");
let (buf, _forty_two) = buf.push_pop(6);
let deque : std::collections::VecDeque<_> = buf.into();
assert!(deque.into_iter().eq(vec![37,23,12,6].into_iter()));
Structs§
- Ring
Buffer - Ring buffer using a boxed array as backing storage. This has the adantage that conversions
from
Vec
or toVecDeque
are nearly free. Main use case of this is as a replacement forstd::collection::VecDeque
in cases where the size is fixed at compile time and one really wants to make invalid states impossible. - Ring
Buffer Iterator Iterator
type returned byRingBuffer::iter()
. Holds a reference to the ring buffer. SeeRingBuffer::iter()
for an example.